home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / ils < prev    next >
Encoding:
Text File  |  1992-02-29  |  66.0 KB  |  2,554 lines

  1. Newsgroups: comp.sources.unix
  2. From: alexj@equinox.unr.edu (Jack Alexander)
  3. Subject: v25i140: ils - interactive "ls" and browser
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: alexj@equinox.unr.edu (Jack Alexander)
  8. Posting-Number: Volume 25, Issue 140
  9. Archive-Name: ils
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of shell archive."
  18. # Contents:  MANIFEST Makefile README get.c get.h ils.1 ils.c ils.h
  19. #   input.c main.c parse.c wildmat.c
  20. # Wrapped by vixie@cognition.pa.dec.com on Sat Feb 29 20:30:04 1992
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  24. else
  25. echo shar: Extracting \"'MANIFEST'\" \(88 characters\)
  26. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  27. MANIFEST
  28. Makefile
  29. README
  30. get.c
  31. get.h
  32. ils.1
  33. ils.c
  34. ils.h
  35. input.c
  36. main.c
  37. parse.c
  38. wildmat.c
  39. END_OF_FILE
  40. if test 88 -ne `wc -c <'MANIFEST'`; then
  41.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  42. fi
  43. # end of 'MANIFEST'
  44. fi
  45. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  46.   echo shar: Will not clobber existing file \"'Makefile'\"
  47. else
  48. echo shar: Extracting \"'Makefile'\" \(524 characters\)
  49. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  50. X# Makefile for ils
  51. X#
  52. CFLAGS = -D$(SYSTEM) -DNODEBUG -g
  53. X# for SYSTEM, make it SYSTEMV for System V  and BSD for Berkely.
  54. SYSTEM = SYSTEMV
  55. X
  56. CC = cc
  57. X
  58. SRCS = main.c ils.c parse.c get.c input.c wildmat.c ils.h get.h
  59. X
  60. MANIFEST = Makefile README $(SRCS)
  61. X
  62. OBJS = main.o ils.o parse.o get.o input.o wildmat.o
  63. X
  64. all: ils
  65. X
  66. clean:
  67. X    rm -f *.o
  68. X    rm -f ils
  69. X
  70. ils:    $(OBJS)
  71. X    $(CC) $(OBJS) -o ils -lcurses -ltermcap
  72. X
  73. main.o:        main.c ils.h
  74. X
  75. ils.o:        ils.c ils.h
  76. X
  77. parse.o:    parse.c
  78. X
  79. get.o:        get.c get.h
  80. X
  81. input.o:    input.c ils.h
  82. X
  83. wildmat.o:    wildmat.c
  84. END_OF_FILE
  85. if test 524 -ne `wc -c <'Makefile'`; then
  86.     echo shar: \"'Makefile'\" unpacked with wrong size!
  87. fi
  88. # end of 'Makefile'
  89. fi
  90. if test -f 'README' -a "${1}" != "-c" ; then 
  91.   echo shar: Will not clobber existing file \"'README'\"
  92. else
  93. echo shar: Extracting \"'README'\" \(3079 characters\)
  94. sed "s/^X//" >'README' <<'END_OF_FILE'
  95. AUTHOR: Jack Alexander
  96. DATE OF LAST MODS: 1/11/91
  97. ANY COMMENTS OR REQUESTS FOR CHANGES WILL BE GREATFULLY ACCEPTED.
  98. X----------------------------------------------------------------------
  99. X(c) 1991 by Jack Alexander
  100. NO WARRANTY OF ANY KIND IS GIVEN WITH THIS PROGRAM, EVEN FOR
  101. XFITNESS OF PURPOSE
  102. X----------------------------------------------------------------------
  103. X
  104. ILS - Interactive "ls" and browser for UNIX systems.
  105. X
  106. This has been tested on BSD-ish and System V machines from several
  107. vendors including Sun, NCR, AT&T, and NeXT (previous version).
  108. X
  109. ils is "interactive ls", a utility to users to easily move around
  110. a directory tree and perform operations on objects in the directories.
  111. XEach user can define their own actions based on key-sequences.
  112. X
  113. The number of built-in commands has been kept to a minimum intentionally.
  114. The idea is to allow total flexibility by allowing people to
  115. use the same tools they've used for years (little shell scripts, etc),
  116. and to just offer them a more efficient, user-friendly way to do it.
  117. I know that this has been done before, but I didn't like the
  118. others ones that much because they were to specific and limiting.
  119. With ils, you can have as powerful or as "safe" a tool as you like,
  120. varying by user.
  121. X
  122. The operations available are defined by the user in $HOME/.ils
  123. in a manner as described in the file ils.1 file which is part
  124. of this release.
  125. X
  126. ils can really replace the use of the shell almost entirely
  127. for many users (I use it myself quite a bit -- I guess that's why
  128. I wrote it).
  129. X
  130. NOTE:
  131. I recommend that you always use the -F option, as it certainly makes
  132. identification of directories easy (puts '/' after each directory).
  133. This can be automatically done by linking ilf to ils, then just using
  134. the name ilf instead of ils.
  135. X
  136. INPUT:
  137. string input is done using a getstring I wrote a few years back.  It's
  138. a little odd, as it was written for people that don't have any vi
  139. experience, as each key has a specific function, and you are always
  140. in insert mode.  Editing instructions can be found in ils.1.
  141. X
  142. OVERVIEW:
  143. X
  144. The user (or administrator) has a file called .ils in their $HOME
  145. directory.  A sample file might be:
  146. X
  147. X# This is a sampel .ils file
  148. help:    man ils
  149. X
  150. m:    more $file
  151. X
  152. V:    vi $file
  153. X
  154. M:    make $input(Make what (RETURN for default)? )
  155. X
  156. mv:    mv $file $input(Rename '$file' to: )
  157. X
  158. XF:    file $file
  159. X
  160. L:    if(latex $prefix);then if(dvijep $prefix);then lpr -B $prefix.jep;fi;fi
  161. X
  162. rm:    rm $file
  163. X
  164. X---------------------- end of example file ------------------
  165. X
  166. In the above file, key sequences "help", "m", "M", "mv", "F", "L", "rm",
  167. and "V" are given actions.
  168. X
  169. X$file is a built-in ils variable (see ils.1) that always contains the
  170. currently selected file (the one pointed at by the cursor).  $prefix,
  171. and $input are also special variables, and there are others.
  172. X
  173. Anyway, if any of the key sequences are eneterd through the keyboard,
  174. and then ENTER or RETURN is pressed, the action defined for
  175. the key sequences in executed, a line at a time, via system(3) calls.
  176. You can multiple action lines for each key sequence, but the example
  177. doesn't contain any.
  178. END_OF_FILE
  179. if test 3079 -ne `wc -c <'README'`; then
  180.     echo shar: \"'README'\" unpacked with wrong size!
  181. fi
  182. # end of 'README'
  183. fi
  184. if test -f 'get.c' -a "${1}" != "-c" ; then 
  185.   echo shar: Will not clobber existing file \"'get.c'\"
  186. else
  187. echo shar: Extracting \"'get.c'\" \(4715 characters\)
  188. sed "s/^X//" >'get.c' <<'END_OF_FILE'
  189. X/* %W% general getstring routine                     */
  190. X/* author: Jack Alexander - this routine may be freely distibuted */
  191. X#include    <curses.h>
  192. X#include    "get.h"
  193. X
  194. get_num(x,y,digits,low,high,number)
  195. int    x,y,digits,low,high,*number;
  196. X{
  197. X    char    buf[80];
  198. X    int    retval;
  199. X
  200. X    buf[0]='\0';
  201. X    noecho();
  202. X    raw();
  203. X    while(1)
  204. X        switch(getst(digits,x,y,buf,digits+1,NULL,NUM_ONLY,NULL)) {
  205. X            case GET_ESCAPE:
  206. X                return(GET_ESCAPE);
  207. X            case GET_DOWN:
  208. X            case GET_RETURN:
  209. X                retval=atoi(buf);
  210. X                if(retval < low || retval>high)
  211. X                    break;
  212. X                *number = retval;
  213. X                echo();
  214. X                noraw();
  215. X                return(0);
  216. X            default:
  217. X                break;
  218. X        }
  219. X}
  220. X
  221. X/* a few hints...    */
  222. X/* idx = current index into string */
  223. X/* cx = current screen x position */
  224. X/* cy = current screen y position */
  225. X/* ix = initial screen x (upon call, where cursor is requested to be placed) */
  226. X/* iy = initial screen y " " " ... */
  227. X/* fw = field width */
  228. X/* mx = max length of string */
  229. X/* sl = string length */
  230. X/* valid = string of acceptable characters within the type passed in gettype */
  231. X/*         if NULL, then all type of characters passed in gettype are allowed */
  232. X
  233. int    idx, cx, cy, ix, iy, fw, mx, sl, rcode;
  234. X
  235. getst(len,sx,sy,str,fl,retlen,gettype,valid)
  236. int    len, sx, sy, fl, *retlen, gettype;
  237. char    *str, *valid;
  238. X{
  239. X    int    c;
  240. X
  241. X
  242. X    rcode = INITIAL;
  243. X    idx=0;
  244. X    cx=ix=sx;
  245. X    cy=iy=sy;
  246. X    mx = len;
  247. X    fw = fl;
  248. X    str[mx]='\0';
  249. X    sl=strlen(str);
  250. X    if(sl!=0) {
  251. X        idx =sl;        /* place cursor at string's end */
  252. X        cx +=sl;
  253. X    }
  254. X#ifdef undef
  255. X    init();
  256. X#endif
  257. X    while(1) {
  258. X        if(gettype==SHOW) {    /* want only to display the string */
  259. X            drawstr(str,0);    /* draw the string */
  260. X#ifdef undef
  261. X            de_init();
  262. X#endif
  263. X            return;
  264. X        }
  265. X        drawstr(str,1);    /* draw the string */
  266. X        c=getch()&0x7f;
  267. X        switch(c) {
  268. X            case GET_CLEAR:
  269. X                clearall(str);
  270. X                break;
  271. X            case GET_ESCAPE:
  272. X                rcode=GET_ESCAPE;
  273. X                break;
  274. X            case GET_UP:
  275. X                rcode=dec_y_pos();
  276. X                break;
  277. X            case GET_DOWN:
  278. X                rcode=inc_y_pos();
  279. X                break;
  280. X            case GET_LEFT:
  281. X                rcode=dec_x_pos();
  282. X                break;
  283. X            case GET_RIGHT:
  284. X                rcode=inc_x_pos(1);
  285. X                break;
  286. X            case GET_DELETE:
  287. X            case GET_DELETE2:
  288. X                remove_char(str);
  289. X                break;
  290. X            case GET_TAB:
  291. X            case GET_RETURN:
  292. X                rcode = GET_RETURN;
  293. X                break;
  294. X            default:
  295. X                switch(gettype) {
  296. X                    case NUM_ONLY: /* numbers only (0-9) */
  297. X                        if(c>='0' && c<='9')
  298. X                            if(in(c,valid))
  299. X                                add_char(str,c);
  300. X                        break;
  301. X                    case LETTER_ONLY:
  302. X                    /* letters a-z and A-Z, and ' ' only */
  303. X                        if(c==' ' || (c>='a' && c<='z') || (c>='A' && c<='Z'))
  304. X                            if(in(c,valid))
  305. X                                add_char(str,c);
  306. X                        break;
  307. X                    case ALL_ALPHA:/* any printable chars */
  308. X                        if(c>=' ' && c<=0x7f)
  309. X                            if(in(c,valid))
  310. X                                add_char(str,c);
  311. X                        break;
  312. X                    default:
  313. X                        if(c>=' ' && c<=0x7f)
  314. X                            add_char(str,c);
  315. X                        break;
  316. X                }
  317. X                break;
  318. X        }
  319. X        if(rcode != INITIAL) {
  320. X#ifdef undef
  321. X            de_init();
  322. X#endif
  323. X            if(retlen != NULL)
  324. X                *retlen = sl;
  325. X            return(rcode);
  326. X        }
  327. X    }
  328. X}
  329. X
  330. dec_y_pos()
  331. X{
  332. X    if(!idx)
  333. X        return(GET_UP);
  334. X    if(iy >= cy) {
  335. X        idx = 0;
  336. X        cx = ix;
  337. X        return(INITIAL);
  338. X    }
  339. X    idx -= fw;
  340. X    cy--;
  341. X    return(INITIAL);
  342. X}
  343. X
  344. inc_y_pos()
  345. X{
  346. X    if(idx>=mx-1 || idx==sl)
  347. X        return(GET_DOWN);
  348. X    if(idx+fw >=  mx) {
  349. X        cx += mx-idx - (mx-sl);
  350. X        idx += mx-idx - (mx-sl);
  351. X#ifdef undef
  352. X        cx += (mx - idx -fw);
  353. X        idx += (mx - idx - fw);
  354. X#endif
  355. X        return(INITIAL);
  356. X    }
  357. X    if(idx+fw > sl) {
  358. X        cx += sl - idx;
  359. X        idx += sl - idx;
  360. X        return(INITIAL);
  361. X    }
  362. X    idx += fw;
  363. X    cy++;
  364. X    return(INITIAL);
  365. X}
  366. X
  367. inc_x_pos(flag)
  368. int    flag;
  369. X{
  370. X    if(flag && idx==sl)
  371. X        return(GET_RIGHT);
  372. X    if(idx == mx)
  373. X        return(GET_RIGHT);
  374. X    cx++;
  375. X    idx++;
  376. X    if(cx >= (ix+fw)) {
  377. X        cx = ix;
  378. X        cy++;
  379. X    }
  380. X    return(INITIAL);
  381. X}
  382. X
  383. dec_x_pos()
  384. X{
  385. X    if(idx==0)
  386. X        return(GET_LEFT);
  387. X    idx--;
  388. X    cx--;
  389. X    if(cx < ix) {
  390. X        cx = fw+ix-1;
  391. X        cy--;
  392. X    }
  393. X    return(INITIAL);
  394. X}
  395. X
  396. add_char(str, c)
  397. char    *str;
  398. char    c;
  399. X{
  400. X    register    int    i;
  401. X
  402. X    if(inc_x_pos(0)!=INITIAL)
  403. X        return;
  404. X    for(i=mx-1;i>=idx;i--)
  405. X        str[i]=str[i-1];
  406. X    str[idx - 1] = c;
  407. X    if(sl!=mx)
  408. X        sl++;
  409. X}
  410. X
  411. remove_char(str)
  412. char    *str;
  413. X{
  414. X    register int i;
  415. X
  416. X    if(idx >= sl) {        /* remove char behind cursor */
  417. X        if(dec_x_pos()!=INITIAL)
  418. X            return;
  419. X        str[sl-1]='\0';
  420. X    }
  421. X    else 
  422. X        for(i=idx;i<mx;i++)
  423. X            str[i]=str[i+1];
  424. X    sl--;
  425. X}
  426. X
  427. drawstr(str,refr)
  428. char    str[];
  429. int    refr;
  430. X{
  431. X    int    i, j, s, yo;
  432. X
  433. X    s=sl;
  434. X    move(iy,ix);
  435. X    for(i=0,yo=1;i<mx;) {
  436. X        if(i>=s) {
  437. X            addch('.');
  438. X            i++;
  439. X        }
  440. X        else if((s-i) < fw) {
  441. X            printw("%s",&str[i]);
  442. X            i += s-i;
  443. X        }
  444. X        else {
  445. X            for(j=0;j<fw;j++)
  446. X                addch(str[i++]);
  447. X        }
  448. X        if((i % fw)==0) {
  449. X            move(iy + yo,ix);
  450. X            yo++;
  451. X        }
  452. X    }
  453. X    move(cy,cx);
  454. X    if(refr)
  455. X        refresh();
  456. X}
  457. X
  458. init()
  459. X{
  460. X    noecho();
  461. X    raw();
  462. X}
  463. X
  464. de_init()
  465. X{
  466. X    noraw();
  467. X    echo();
  468. X}
  469. X
  470. in(ch,allow)
  471. char    ch, allow[];
  472. X{
  473. X    register int    i;
  474. X
  475. X    if(allow == NULL)
  476. X        return(1);
  477. X    for(i=0;i<strlen(allow);i++)
  478. X        if(ch==allow[i])
  479. X            return(1);
  480. X    return(0);
  481. X}
  482. X
  483. clearall(str)
  484. char    str[];
  485. X{
  486. X    sl=idx=0;
  487. X    cx=ix;
  488. X    cy=iy;
  489. X    str[0]='\0';
  490. X}
  491. END_OF_FILE
  492. if test 4715 -ne `wc -c <'get.c'`; then
  493.     echo shar: \"'get.c'\" unpacked with wrong size!
  494. fi
  495. # end of 'get.c'
  496. fi
  497. if test -f 'get.h' -a "${1}" != "-c" ; then 
  498.   echo shar: Will not clobber existing file \"'get.h'\"
  499. else
  500. echo shar: Extracting \"'get.h'\" \(797 characters\)
  501. sed "s/^X//" >'get.h' <<'END_OF_FILE'
  502. X/* defines for my getstring routine */
  503. X/* %W% */
  504. X
  505. X#define INITIAL    0
  506. X#define GET_CLEAR    0x03    /* control c */
  507. X#define    GET_UP        0x0b    /* control k */
  508. X#define GET_DOWN    0x0a    /* control j */
  509. X#define GET_LEFT    0x08    /* control h */
  510. X#define GET_RIGHT    0x0c    /* control l */
  511. X#define GET_TAB        0x09    /* control i */
  512. X#define GET_RETURN    0x0d    /* control m */
  513. X#define GET_DELETE      24    /* control x */
  514. X#define GET_DELETE2    0x7f    /* delete key on most terminals */
  515. X#define GET_ESCAPE    0x1b    /* escape */
  516. X
  517. X/* types of characters that can be specified for getstring input */
  518. X#define SHOW        0 /* only show the string, don't ask for input */
  519. X#define NUM_ONLY    1 /* only numeric characters 0-9 */
  520. X#define LETTER_ONLY    2 /* only letters a-z, A-Z and space (' ') */
  521. X#define ALL_ALPHA    3 /* all printable ascii characters are permitted */
  522. END_OF_FILE
  523. if test 797 -ne `wc -c <'get.h'`; then
  524.     echo shar: \"'get.h'\" unpacked with wrong size!
  525. fi
  526. # end of 'get.h'
  527. fi
  528. if test -f 'ils.1' -a "${1}" != "-c" ; then 
  529.   echo shar: Will not clobber existing file \"'ils.1'\"
  530. else
  531. echo shar: Extracting \"'ils.1'\" \(7789 characters\)
  532. sed "s/^X//" >'ils.1' <<'END_OF_FILE'
  533. X.PU
  534. X.TH ILS 1 local
  535. X.SH NAME
  536. ils \- interactive directory browser and visual shell
  537. X.SH SYNOPSIS
  538. X.ll +8
  539. X.B ils \[-aFeTr<rows>c<columns> \[title\]\] \[ pattern1 pattern2 \.\.\. patternN \]
  540. X.ll -8
  541. X.br
  542. X.SH DESCRIPTION
  543. X.B ils
  544. was orginally just a driectory browsing utility to allow users
  545. to move around the system, descending into directories through
  546. a visually-oriented interface.
  547. X
  548. Since the original implementation, the functionality of
  549. X.B ils
  550. has been expanded to allow operations to be performed on the files in the
  551. directories currently being examined.  Each user can define their own set of
  552. operations using built-in variables, environment variables, as well as
  553. keyboard input.  By creating a file, ``.ils" in the $HOME directory,
  554. each user can define what sequence of keys invokes a set of shell
  555. operations.
  556. X
  557. There are several options, some of which corresponds to the option of
  558. the same name in the
  559. X.B ls(1)
  560. command:
  561. X.TP
  562. X.BI \-a 
  563. List all entries; usually `.', `..' and all files that start with a `.'
  564. are suppresed. This is the default if the last character of the name
  565. of the program is an `a' (i.e., linking ila to ils).
  566. X.TP
  567. X.BI \-F
  568. Cause directories to be marked with a trailing `/' and executable files
  569. to be marked with a trailing `*'.  This is the default if the last
  570. character of the name of the program is a `f' (i.e., linking ilf to ils).
  571. X.TP
  572. X.BI \-e
  573. XEcho all commands as they are executed.
  574. X.TP
  575. X.BI \-T\ \<title\>
  576. Print a title on top of the window or screen.
  577. X.TP
  578. X.BI \-r
  579. Change the vertical size of the ils window from the default.  The default is the
  580. size of the screen upon calling ils.  If using this option, the
  581. number of rows must immediately follow, with no white space (i.e., ils -r10).
  582. X.TP
  583. X.BI \c
  584. Change the horizontal size of the ils window from the default.  The default
  585. is the size of the screen upon calling ils.  If using this option, the
  586. number of columns must immediately follow, with no white space (i.e., ils -r60).
  587. X
  588. X.SH WILDCARDING
  589. Patterns can be used in to match files, just as in ls(1).  To
  590. pass a pattern to ils, and to avoid the shell from
  591. expanding it prior to invoking ils, the user can surround
  592. the pattern with quotes (i.e., 'ils "*.c"'  instead of ils *.c).
  593. This will insure that the pattern match is done on every directory
  594. descended into during the execution of ils.  Otherwise, if no
  595. quotes are used, the shell will expand the wildarding and pass ils
  596. all filenames that match the pattern in the current working directory.
  597. Any directory descended into that do not contain any files of the same name
  598. will appear to the user as an empty directory.
  599. X
  600. X.B ils
  601. wildcarding works exactly the same as sh(1), csh(1), and ksh(1)
  602. wildcarding (thanks to Rich Salz for the wildcarding routine).
  603. X
  604. X.SH THE .ils FILE
  605. XEach user can set up their own .ils file in their home ($HOME) directory
  606. to define their own key sequences and corresponding actions related to
  607. those key sequences.  The .ils file has the following format:
  608. X
  609. X.nf
  610. key_sequence:   command line 1
  611. X                command line 2
  612. X                     ...
  613. X                command line n
  614. X.fi
  615. X
  616. This tells
  617. X.B ils
  618. that when the key sequence is entered, execute the shell commands
  619. in command lines 1 through n.  One current limitation
  620. X.B ils
  621. has is that each command line is executed seperately, so that
  622. no interdependent lines can be used.  A call to system(3) is made on
  623. each line, so a new shell comes into existance for each line.
  624. Any environmental changes made such as shell variable assignment
  625. or change of working directory are lost after each command.
  626. You can, however, have multiple shell commands on one line by using
  627. semicolons delimiting seperate commands.
  628. X
  629. All lines that have a `#' character as the first character are
  630. assumed to be comments and are skipped.
  631. X.SH USING ils
  632. upon execution, the user will see a listing of the directory,
  633. very similar to the output of the 
  634. X.B ls(1)
  635. command.  On the top line is the path of the current directory.
  636. If possible,
  637. X.B ils
  638. will display the full path of the current working directory.  If the
  639. path exceeds the width of the screen or window, it will be truncated.
  640. Since the right-most characters of a pathname are usually of the most interest,
  641. the truncation is done at the left end.  As many characters as will fit
  642. are shown, and the path is preceeded by "...".
  643. X
  644. One file is always the "current file", it is pointed at by the
  645. X.B ils
  646. cursor `>'.  To change the current file, there are cursor movement
  647. keys.  The defaults are h,j,k and l (as in vi(1)).  If a directory
  648. has been made the current file, the user can descend into the directory
  649. by pressing the RETURN or ENTER key.  Once the user has descended into
  650. a directory the directory becomes the current working directory.  The
  651. current path on the top line will be updated, and the contents of the
  652. directory will be shown on the screen.
  653. X
  654. The user can also ``force" a command from the keyboard by pressing
  655. the ':' key.  This will prompt the user for a line of input which will
  656. be scaned for variable substitution, then executed via a call to system(3).
  657. This can be useful in that it makes it so that the user rarely has to
  658. leave ils to perform a command (i.e, ":rm *.o" will invoke a shell
  659. and remove all file ending in ".o"; ":more $file" will invoke a shell
  660. and display the cuurently selected file via the more(1) command).
  661. X
  662. To go back up one level (i.e., cd ..), press ESCAPE.
  663. X
  664. To exit ils, press control-D.
  665. X
  666. X.SH KEYBOARD INPUT and STRING EDITING
  667. When entering string from the keyboard, there is one important
  668. thing to remember: you are always in insert mode.
  669. The string editing routines in
  670. X.B ils
  671. use the following keys:
  672. X.TP
  673. X.BI ESCAPE
  674. Abort editing this string
  675. X.TP
  676. X.BI control-x
  677. Delete a character
  678. X.TP .BI
  679. X.BI control-c
  680. Clear entire string
  681. X.TP
  682. X.BI left-arrow
  683. Go left one character within the string
  684. X.TP
  685. X.BI ENTER (or RETURN)
  686. The first ENTER puts you at the end of the string, the second ENTER
  687. will pass the string back to ils for processing, and terminate the
  688. string edit.  If you are already on the last character in the string,
  689. then the first press of ENTER will enter the string.
  690. X
  691. All of the command keys used in editing can be easily changed by modifying
  692. the file "ils.h", then re-making ils.  In a later release, it is hoped that
  693. each user can define their editing key within their ".ils" file.
  694. X
  695. X.SH VARIABLES AND BUILT-IN COMMANDS
  696. X.B ils
  697. has several variables and commands built-in:
  698. X.TP
  699. X.BI $file
  700. the name of the file currently selected
  701. X.TP
  702. X.BI $prefix
  703. the prefix (all characters up to the first `.') of the
  704. file currently selected
  705. X.TP
  706. X.BI $path
  707. the current directory being viewed
  708. X.TP
  709. X.BI $all_files
  710. all files in the directory being viewed
  711. X.TP
  712. X.BI $input(prompt)
  713. value typed in from keyboard after user is prompted with the string
  714. contained in prompt (variable names can be used in contructing prompt)
  715. X.TP
  716. X.BI $ENVIRONMENT_VARIABLE
  717. the value of any environment variable can be used (i.e., $HOME will
  718. be substituted with the value of $HOME in the user's environment).
  719. X.B ils
  720. will use it's own variable values before checking for any existing
  721. environment variables.  This means that is the user wants to
  722. use the value of the variable $file from his environment,
  723. X.B ils
  724. will use the name of the current file instead, since $file is
  725. a built-in variable.
  726. X
  727. X.SH SAMPLE .ils FILE
  728. X
  729. X
  730. X.nf
  731. X# This is a sample .ils file
  732. X#
  733. cc:    cc $file
  734. X
  735. RM:    rm $file
  736. X
  737. V:    vi $file
  738. X
  739. X# make, can change default by entering an alernative
  740. X# (i.e., "make install")
  741. M:    make $input(Make what (RETURN is default)? )
  742. X
  743. X# rename the file
  744. mv:    mv $file (Rename $file to: )
  745. X
  746. X# LateX a file and print it
  747. L:    latex $prefix
  748. X    dvijep $prefix
  749. X    lpr -b $prefix.jep
  750. X
  751. X# look at my definition file
  752. defs:    more $HOME/.ils
  753. X.fi
  754. X
  755. X.SH RELEASE NOTES
  756. X
  757. X.PP
  758. X.SH "AUTHOR"
  759. Jack Alexander, (jack@jimi.cs.unlv.edu), (jack@equinox.unr.edu)
  760. X.SH "BUGS"
  761. No known bugs
  762. END_OF_FILE
  763. if test 7789 -ne `wc -c <'ils.1'`; then
  764.     echo shar: \"'ils.1'\" unpacked with wrong size!
  765. fi
  766. # end of 'ils.1'
  767. fi
  768. if test -f 'ils.c' -a "${1}" != "-c" ; then 
  769.   echo shar: Will not clobber existing file \"'ils.c'\"
  770. else
  771. echo shar: Extracting \"'ils.c'\" \(25940 characters\)
  772. sed "s/^X//" >'ils.c' <<'END_OF_FILE'
  773. X/**************************************************************************
  774. X * ils - interactive "ls" library for ascii terminals.
  775. X *
  776. X * Subroutine ils expects variable "rows", and "cols" to be set prior to
  777. X * calling.  rows should contain the verticle size of the window to
  778. X * be used, and cols should contain horizontal size (in characters).
  779. X *
  780. X *
  781. X * Author: Jack Alexander
  782. X *       jack@marley
  783. X *
  784. X */
  785. X#include    "ils.h"
  786. X
  787. X#include <curses.h>
  788. X#include <stdio.h>
  789. X#include <sys/dir.h>
  790. X#include <fcntl.h>
  791. X#include <errno.h>
  792. X
  793. X#include    "get.h"           /* need key definitions from getstring routine */
  794. X
  795. extern    char    *pnam;        /* program name */
  796. X
  797. int    a_num, a_ind;            /* work variables for argument processing */
  798. int    syms=0;                /* number of symbols in table */
  799. struct    symbol    *symtab[MAX_SYMBOLS]; /* symbol table */
  800. char    *args[ILS_MAX_ARGS];        /* argument list */
  801. int    modes;                /* hold behavioral data */
  802. X
  803. char    cur_path[MAXPATH];        /* current path */
  804. X
  805. X
  806. X/* interactive directory browser -- main routine 
  807. X**
  808. X** variable pattern in a two dimensional array containing all of the patterns
  809. X** to use for pattern matching.  If pattern[0] == NULL, then no
  810. X** patterns are used, and all files are shown.
  811. X**
  812. X** variable path is a string containing the path of the directory from which
  813. X** browsing will begin (typically, same as pwd(1)).
  814. X**
  815. X** ulx, uly, lrx, and lry are the coordinates (in screen coordinates where
  816. X** units are characters.
  817. X**
  818. X** m is an integer which may contain any behavioral charactaristics.
  819. X** various bits, as described in ils.h can be ored into this variable to
  820. X** change the behavior of ils.
  821. X**
  822. X** title is a string which is displayed on the top line of the window.  If
  823. X** title is NULL, then no title is shown, and you get an extra line for
  824. X** editing.
  825. X**/
  826. ils(pattern,path,ulx,uly,lrx,lry,m,title)
  827. char    *pattern[],*path,*title;
  828. int    ulx, uly, lrx, lry, m;
  829. X{
  830. X    struct    d_entry    *top;    /* the very top of the known directory tree */
  831. X
  832. X    modes = m;        /* makes user defined modes global */
  833. X    top = (struct d_entry *) NULL;    /* haven't read any directories yet */
  834. X    clear();
  835. X    read_ils_defines();    /* read this user's definitions */
  836. X    read_directory(pattern,path,&top); /* read in current directory */
  837. X    edit_directory(pattern,path,&top,ulx,uly,lrx,lry,title); /* do it */
  838. X}
  839. X
  840. X/* read_ils_defines() looks and the ".ils" file for the user.  This file
  841. X   contains all user-specific key sequences and correspoding actions for
  842. X   the key sequences. */
  843. read_ils_defines()
  844. X{
  845. X    char    *getenv(), *a, dummy[MAXPATH];
  846. X    FILE    *fopen(), *fp;
  847. X    int    lnum=0;
  848. X
  849. X    a=getenv("HOME");        /* get path to user's home directory */
  850. X    sprintf(dummy,"%s/.ils",a);    /* set up path to the .ils file */
  851. X    if((fp=fopen(dummy,"r"))==NULL)
  852. X        return;            /* no ".ils" file in home directory */
  853. X    while(fgets(dummy,MAXPATH,fp)!=NULL) {
  854. X        lnum++;            /* line number counter */
  855. X        if(dummy[0]=='#')
  856. X            continue;    /* a comment line */
  857. X        parse_line(dummy,lnum); /* enter into symbol table */
  858. X    }
  859. X    fclose(fp);
  860. X}
  861. X
  862. X#ifdef BSD
  863. X/******
  864. X * Berkeley UNIX version. read directory reads all files in the current
  865. X * directory.
  866. X */
  867. read_directory(pattern,path,dptr)
  868. char    *pattern[],path[];
  869. struct    d_entry    **dptr;
  870. X{
  871. X    DIR    *dp, *opendir();
  872. X    struct    direct    *dirptr, *readdir();
  873. X
  874. X    if(chdir(path)<0)
  875. X        return;        /* can't change to desired directory */
  876. X    if((dp=opendir("."))==NULL)
  877. X        return;        /* can't open the directory file itself */
  878. X    while((dirptr=readdir(dp))!=NULL)    /* end of directory */
  879. X        add_entry(pattern,dirptr->d_fileno,dirptr->d_name,dptr);
  880. X    closedir(dp);
  881. X}
  882. X#endif BSD
  883. X
  884. X#ifdef SYSTEMV
  885. X/* SYSTEM V Unix version of the read_directory routine.    */
  886. read_directory(pattern,path,dptr)
  887. char    *pattern[],path[];
  888. struct    d_entry    **dptr;
  889. X{
  890. X    struct    direct    d;
  891. X    int    fd;
  892. X
  893. X    if(chdir(path)<0)    /* can't change to the desired directory */
  894. X        return;
  895. X    if((fd=open(".",O_RDONLY))<0)    /* can't open the directory file */
  896. X        return;
  897. X    while(read(fd,&d,sizeof(struct direct)) == sizeof(struct direct))
  898. X        add_entry(pattern,d.d_ino,d.d_name,dptr); /* add file */
  899. X    close(fd);
  900. X}
  901. X#endif SYSTEMV
  902. X
  903. X/* showpath displays the string in "path" on the top line of the window.
  904. X   The top line is defined in ulx, ily.  Only as much of the path as
  905. X   can be seen is displayed, the rest is cust out. */
  906. showpath(path,ulx, uly, lrx, lry)
  907. char    path[];
  908. int    ulx, uly, lrx, lry;
  909. X{
  910. X    int    l;
  911. X    char    dummy[80];
  912. X
  913. X    standout();    /* invert the line */
  914. X    move(uly,ulx);    /* move to top line of the window */
  915. X    if((l=strlen(path))>(lrx-uly-1)) {    /* is string too long? */
  916. X        /* if string is too long, truncate it.  preceed all truncated
  917. X           paths with "..." to show user that the path was indeed
  918. X           truncated. */
  919. X        sprintf(dummy,"...%c%d.%ds",'%',(lrx-ulx-3),(lrx-ulx-3));
  920. X        printw(dummy,path+(l-(lrx-ulx-3)));    /* print path */
  921. X    }
  922. X    else    /* string is not too long, just print it */
  923. X        printw(path);
  924. X    standend();   /* end inverted mode */
  925. X    clrtoeol();   /* get rid of standend char on some types of terminals */
  926. X}
  927. X
  928. X/* display an error message on the top line of the window, wait for RETURN
  929. X   key to be pressed so that user can acknowledge the error */
  930. ils_error(msg,ulx,uly,lrx,lry)
  931. char    msg[];
  932. int    ulx, uly, lrx, lry;
  933. X{
  934. X    int    l;
  935. X    char    dummy[80];
  936. X
  937. X    standout();        /* all errors in inverse mode */
  938. X    move(uly,ulx);        /* go to top line */
  939. X    sprintf(dummy,">> %s <<  Press RETURN...",msg);
  940. X    if((l=strlen(dummy))>(lrx-uly-1)) {  /* does message need truncation? */
  941. X        if(strlen(msg) > (lrx-uly-1)) {
  942. X            /* truncate the message. Preceed truncated with "..." */
  943. X            sprintf(dummy,"...%c%d.%ds",'%',(lrx-ulx-3),(lrx-ulx-3));
  944. X            printw(dummy,msg+(l-(lrx-ulx-3)));
  945. X            
  946. X        }
  947. X        else
  948. X            strcpy(dummy,msg);    /* no truncation needed */
  949. X    }
  950. X    printw(dummy);
  951. X    standend();    /* end inverse mode */
  952. X    refresh();
  953. X    ils_wait_key(ILS_ENTER);    /* wait for RETURN key to be pressed */
  954. X}
  955. X
  956. X/* wait for key (passed in variable 'c') to be pressed.  Keep asking
  957. X   for more keys until the one waited for is pressed. */
  958. ils_wait_key(c)
  959. int    c;
  960. X{
  961. X    while((getch()&0x7f)!=c);
  962. X}
  963. X
  964. X/* edit a directory, using a rectangle in the screen with (ulx, uly) as
  965. X   the coordinates of the upper-left corner of the rectangle, and
  966. X   (lrx, lry) as the lower-right corner of the rectangle.  title is
  967. X   a character string that will be printed in the top line of the rectangle,
  968. X   unless a NULL is passed, in which case nothing is printed, and you
  969. X   have another line to use as part of the directory. */
  970. X
  971. edit_directory(pattern,path,dptr,ulx,uly,lrx,lry,title)
  972. char    *pattern[],path[];
  973. struct    d_entry    **dptr;
  974. int    ulx, uly, lrx, lry;
  975. char    *title;
  976. X{
  977. X    static    int    level=0;
  978. X    char    newpath[80], trailer, *p, line[MAXPATH], this_dir[MAXPATH],
  979. X        last_active[MAXPATH];
  980. X    struct    d_entry *cur, *t, *active_list[ILS_MAX_ENTRIES];
  981. X    int    height, width, widest, entries, i, j, horiz_fit, vert_fit,
  982. X        x, y, more_line, first_visible, orig_uly,
  983. X        column_height, cur_entry, state, next_state, c,
  984. X        last_x, last_y, z, up_x, up_y, down_x, down_y,
  985. X        done, new_entries, low, high, middle;
  986. X
  987. X    clear();
  988. X    raw();        /* need characters AS THEY ARE PRESSED */
  989. X    noecho();    /* don't show user's input */
  990. X
  991. X    orig_uly = uly;
  992. X    if(title != (char *)NULL)     /* is there a title? */
  993. X        uly++;    /* account for title line */
  994. X    uly++;        /* account for "current directory" line */
  995. X    
  996. X    height = lry - uly;    /* height of window */
  997. X    width = lrx - ulx;    /* width of window */
  998. X
  999. X    strcpy(cur_path,path);    /* make path globally known */
  1000. X
  1001. X    level++;        /* count the levels down */
  1002. X
  1003. X    state = ILS_INITIAL;
  1004. X    next_state = ILS_INITIAL2;
  1005. X    cur_entry = 0;
  1006. X
  1007. X    while(1) {    /* loop will end with an exit() call */
  1008. X      switch(state) {
  1009. X        case ILS_INITIAL:
  1010. X        cur = *dptr; /* get all entries in directory into a sorted list */
  1011. X        widest = 6;  /* default longest string length */
  1012. X        entries = first_visible = 0;
  1013. X        /* loop through and find the longest filename in the list */
  1014. X        while(cur != (struct d_entry *)NULL) {
  1015. X            if((i=strlen(cur->name)) > widest)
  1016. X                widest = i;    /* found a longer string */
  1017. X            active_list[entries++] = cur;
  1018. X            cur = cur->next;    /* get next in list */
  1019. X        }
  1020. X        /* get number of strings that can fit => how many columns */
  1021. X        horiz_fit = width / (widest+2);
  1022. X        column_height = entries / horiz_fit + ((entries%horiz_fit)==0? 0:1);
  1023. X        vert_fit = lry-uly; /* how many can fit verticall into window */
  1024. X        if(vert_fit > column_height)
  1025. X            vert_fit = column_height;    /* safeguard */
  1026. X
  1027. X        state = next_state;
  1028. X        break;
  1029. X
  1030. X        case ILS_INITIAL2:
  1031. X        if(!entries) {    /* is this an empty directory? */
  1032. X            showpath(path,ulx,orig_uly+(title==NULL? 0:1),lrx,lry);
  1033. X            ils_error("EMPTY DIRECTORY",ulx,orig_uly,lrx,lry);
  1034. X            level--;
  1035. X            return;    /* empty: allow no editing */
  1036. X        }
  1037. X        state = ILS_TOTAL_DRAW;    /* redraw screen */
  1038. X        break;
  1039. X
  1040. X        case ILS_FIND_CURSOR:    /* locate best place for cursor */
  1041. X        done = 0;
  1042. X        low = 0;        /* base value for binary search */
  1043. X        high = entries;        /* high value for binary search */
  1044. X        /* binary search to position where the cursor should be */
  1045. X        while(!done) {    /* binary search to the place to put cursor */
  1046. X            middle = (low+high)/2;
  1047. X            i = strcmp(last_active,active_list[middle]->name);
  1048. X            if(i==0)
  1049. X                done = 1;    /* found entry! */
  1050. X            if(i<0) {
  1051. X                if(middle==high) /* found where to put cursor */
  1052. X                    done=1;
  1053. X                else
  1054. X                    high = middle; /* try lower half */
  1055. X            }
  1056. X            else {
  1057. X                if(middle==low) /* found where to put cursor */
  1058. X                    done=1;
  1059. X                else
  1060. X                    low = middle; /* try upper half */
  1061. X            }
  1062. X        }
  1063. X        /* middle is now equal to entry number where cursor should be */
  1064. X        cur_entry = middle;
  1065. X        first_visible = 0;    /* for now, top line shown is line 0 */
  1066. X        i = middle % column_height;  /* get offset from top of column */
  1067. X        if(i>=vert_fit)        /* is the active entry off the screen? */
  1068. X            first_visible = i-vert_fit+1;/* YES make it visible */
  1069. X        if(first_visible<0 || first_visible>=entries || first_visible>=vert_fit)
  1070. X            first_visible = i;    /* safeguard */
  1071. X        if(first_visible >= entries)    /* another safeguard */
  1072. X            first_visible;
  1073. X        state = ILS_INITIAL2;
  1074. X        break;
  1075. X
  1076. X        case ILS_TOTAL_DRAW:    /* redraw the whole window */
  1077. X        clear();
  1078. X        if(title != NULL) {    /* is there a title to display? */
  1079. X            move(orig_uly,ulx);
  1080. X            clrtoeol();
  1081. X            printw("%s",title);    /* display the title */
  1082. X        }
  1083. X        /* display the path either just below the title, or on top */
  1084. X        showpath(path,ulx,orig_uly+(title==NULL? 0:1),lrx,lry);
  1085. X        case ILS_DRAW:        /* show files in directory */
  1086. X        up_x=up_y=down_x=down_y= -1;
  1087. X        for(i=0,z=first_visible;i<horiz_fit;i++) {
  1088. X            for(j=0;j<vert_fit && z<entries;j++,z++) {
  1089. X                y=uly+j;
  1090. X                x=1+ulx+(width/horiz_fit)*i;
  1091. X                move(y,x);
  1092. X                if(!i)
  1093. X                    clrtoeol();
  1094. X                if(!i && !j && first_visible) {
  1095. X                    standout();
  1096. X                    printw("< more",first_visible*horiz_fit+1);
  1097. X                    standend();
  1098. X                    up_x = x;
  1099. X                    up_y = y;
  1100. X                }
  1101. X                else {
  1102. X                    trailer=' ';
  1103. X                    if(modes & ILS_F_TYPE) {
  1104. X                        if(active_list[z]->stat.st_mode & 040000)
  1105. X                            trailer='/';
  1106. X                        else if(active_list[z]->stat.st_mode & 0100)
  1107. X                            trailer='*';
  1108. X                    }
  1109. X                    printw("%s%c",active_list[z]->name,trailer);
  1110. X
  1111. X                }
  1112. X            }
  1113. X            z+=column_height-vert_fit;
  1114. X        }
  1115. X        if((first_visible+vert_fit) < column_height) {
  1116. X            y=uly+vert_fit-1;
  1117. X            x=1+ulx+(width/horiz_fit)*(horiz_fit-1);
  1118. X            move(y,x);
  1119. X            standout();
  1120. X            printw("more >");
  1121. X            standend();
  1122. X            clrtoeol();
  1123. X            down_x = x;
  1124. X            down_y = y;
  1125. X        }
  1126. X
  1127. X        refresh();
  1128. X        state = ILS_SHOW_CURSOR;
  1129. X        next_state = ILS_KEYBOARD;
  1130. X        break;
  1131. X      case ILS_SHOW_PATH:
  1132. X        showpath(path,ulx,orig_uly+(title==NULL? 0:1),lrx,lry);
  1133. X      case ILS_MOVE_CURSOR:
  1134. X        move(last_y,last_x);
  1135. X        addch(' ');
  1136. X      case ILS_SHOW_CURSOR:
  1137. X        last_y=y=uly + cur_entry%column_height-first_visible;
  1138. X        last_x=x=ulx + (width/horiz_fit) * (cur_entry / column_height);
  1139. X        if((x+1)==up_x && y==up_y) {
  1140. X            first_visible--;
  1141. X            state = ILS_DRAW;
  1142. X            break;
  1143. X        }
  1144. X        if((x+1)==down_x && y==down_y) {
  1145. X            first_visible++;
  1146. X            state = ILS_DRAW;
  1147. X            break;
  1148. X        }
  1149. X        move(y,x);
  1150. X        addch('>');
  1151. X        move(y,x);
  1152. X        refresh();
  1153. X        state = next_state;
  1154. X        break;
  1155. X      case ILS_KEYBOARD:
  1156. X        switch((c=(getch()&0x7f))) {
  1157. X            case ILS_ESCAPE:    /*  go back up or QUIT! */
  1158. X                if(level==1)
  1159. X                    state=ILS_ASCEND;
  1160. X                else
  1161. X                    state = ILS_EXIT;
  1162. X                break;
  1163. X            case ILS_EXIT_KEY:        /* QUIT NOW! */
  1164. X                ils_exit(1);
  1165. X                break;
  1166. X            case ILS_ENTER:
  1167. X            case ILS_RETURN:    /* descend into a directory */
  1168. X                if(active_list[cur_entry]->stat.st_mode & 040000) {
  1169. X                    if(strcmp(active_list[cur_entry]->name,".")==0) {
  1170. X                        flash(); /* change to current directory */
  1171. X                        break;
  1172. X                    }
  1173. X                    if(strcmp(active_list[cur_entry]->name,"..")==0) {
  1174. X                        if(level==1)
  1175. X                            state = ILS_ASCEND;
  1176. X                        else
  1177. X                            state = ILS_EXIT;
  1178. X                        break;
  1179. X                    }
  1180. X                    if(path[1]=='\0')
  1181. X                        sprintf(newpath,"/%s",active_list[cur_entry]->name);
  1182. X                    else
  1183. X                        sprintf(newpath,"%s/%s",path,active_list[cur_entry]->name);
  1184. X                    strcpy(last_active,active_list[cur_entry]->name);
  1185. X                    if(active_list[cur_entry]->contents == (struct d_entry *)NULL) {
  1186. X                        read_directory(pattern,newpath,&(active_list[cur_entry]->contents));
  1187. X                    }
  1188. X                    else {
  1189. X                        chdir(newpath);
  1190. X                        strcpy(cur_path,newpath);
  1191. X                        re_read_dir(pattern,&(active_list[cur_entry]->contents));
  1192. X                    }
  1193. X                    refresh();
  1194. X                    edit_directory(pattern,newpath,&(active_list[cur_entry]->contents),ulx,orig_uly,lrx,lry,title);
  1195. X                    chdir(path);    /* back up */
  1196. X                    strcpy(cur_path,path);
  1197. X                    state = ILS_INITIAL;
  1198. X                    if((new_entries=re_read_dir(pattern,dptr))!=entries) 
  1199. X                        next_state = ILS_FIND_CURSOR;
  1200. X                    else
  1201. X                        next_state = ILS_INITIAL2;
  1202. X                }
  1203. X                break;
  1204. X            case ILS_UP:        /* move cursor up */
  1205. X                if(cur_entry==0 || (cur_entry%column_height)==0)
  1206. X                    break; /* can't move up one */
  1207. X                cur_entry--;
  1208. X                y=uly+cur_entry%column_height-first_visible;
  1209. X                 if(y<uly) {
  1210. X                    state = ILS_DRAW;
  1211. X                    first_visible--;
  1212. X                }
  1213. X                else {
  1214. X                    state = ILS_MOVE_CURSOR;
  1215. X                    next_state = ILS_KEYBOARD;
  1216. X                }
  1217. X                break;
  1218. X            case ILS_DOWN:        /* move cursor down */
  1219. X                if(cur_entry==(entries-1) || (cur_entry%column_height)==column_height-1)
  1220. X                    break;    /* can't move down one */
  1221. X                cur_entry++;
  1222. X                y=uly+cur_entry%column_height-first_visible;
  1223. X                if(y>=lry) {
  1224. X                    state = ILS_DRAW;
  1225. X                    first_visible++;
  1226. X                }
  1227. X                else {
  1228. X                    state = ILS_MOVE_CURSOR;
  1229. X                    next_state = ILS_KEYBOARD;
  1230. X                }
  1231. X                break;
  1232. X            case ILS_RIGHT:        /* move cursor right */
  1233. X                if(cur_entry+column_height >= entries)
  1234. X                    break;    /* can't move right */
  1235. X                else {
  1236. X                    cur_entry+=column_height;
  1237. X                    state = ILS_MOVE_CURSOR;
  1238. X                    next_state = ILS_KEYBOARD;
  1239. X                }
  1240. X                break;
  1241. X            case ILS_LEFT:        /* move cursor left */
  1242. X                if(cur_entry-column_height < 0)
  1243. X                    break;    /* can't move left */
  1244. X                else {
  1245. X                    cur_entry-=column_height;
  1246. X                    state = ILS_MOVE_CURSOR;
  1247. X                    next_state = ILS_KEYBOARD;
  1248. X                }
  1249. X                break;
  1250. X            case ILS_REDRAW:    /* redraw the screen */
  1251. X            case ILS_REDRAW_ALT:    /* alternate character */
  1252. X                state = ILS_TOTAL_DRAW;
  1253. X                break;
  1254. X                case ILS_ENV:        /* display symbol table */
  1255. X                display_symtab();
  1256. X                state = ILS_TOTAL_DRAW;
  1257. X                break;
  1258. X            case ILS_FORCE_KEYBOARD: /* force us into keyboard mode */
  1259. X            default:
  1260. X                if(keybd(c,ulx,orig_uly+(title==NULL? 0:1),lrx,lry,line)) {
  1261. X                    strcpy(last_active,active_list[cur_entry]->name);
  1262. X                    process_input(c,active_list,cur_entry,entries,line,ulx,orig_uly+(title==NULL? 0:1),lrx);
  1263. X                    state = ILS_INITIAL;
  1264. X                    if((new_entries=re_read_dir(pattern,dptr))!=entries)
  1265. X                        next_state = ILS_FIND_CURSOR;
  1266. X                    else
  1267. X                        next_state = ILS_INITIAL2;
  1268. X                    showpath(path,ulx,orig_uly+(title==NULL? 0:1),lrx,lry);
  1269. X                }
  1270. X                else
  1271. X                    state = ILS_SHOW_PATH;
  1272. X                break;
  1273. X        }
  1274. X        break;
  1275. X        case ILS_ASCEND:            /* up into a new directory */
  1276. X        if(path[1]=='\0') {        /* at root (/) ? */
  1277. X            flash();        /* can't go up any higher! */ 
  1278. X            state = ILS_KEYBOARD;    /* back to input mode */
  1279. X            break;
  1280. X        }
  1281. X        strcpy(newpath,path);
  1282. X        /* find the first '/' character from the right, then chop the
  1283. X           path from that point on.  This is to make a path like:
  1284. X                /usr/local/bin
  1285. X           into
  1286. X                /usr/local
  1287. X         */
  1288. X        for(i=strlen(path)-1;i && newpath[i]!='/';i--);
  1289. X        if(i==0) {    /* i==0 if we are one level down from root */
  1290. X            strcpy(newpath,"/");    /* make root the new path */
  1291. X            strcpy(this_dir,&(path[1]));
  1292. X        }
  1293. X        else {
  1294. X            newpath[i]='\0';    /* up one level in the path */
  1295. X            strcpy(this_dir,&(newpath[i+1]));
  1296. X        }
  1297. X        if(this_dir[0]=='\0')    /* make sure not a  null string */
  1298. X            break;    /* a little safeguard */
  1299. X        cur = (struct d_entry *) NULL;    /* ready to read a new dir */
  1300. X        read_directory(pattern,newpath,&cur); /* read it */
  1301. X        t = cur;    /* find the entry in the new directory that
  1302. X                   corresponds to this directory's name. */
  1303. X        strcpy(last_active,this_dir);    /* for finding cursor pos */
  1304. X        for(cur = (*dptr);cur!=(struct d_entry *)NULL;) {
  1305. X            if(strcmp(cur->name,this_dir)==0) {
  1306. X                /* found it.  assign contents to this entry */
  1307. X                cur->contents = (*dptr);
  1308. X                cur = (struct d_entry *) NULL;
  1309. X            }
  1310. X            else    /* try next one */
  1311. X                cur = cur->next;
  1312. X        }
  1313. X        (*dptr) = t;    /* make this the new "top of tree" pointer */
  1314. X        strcpy(cur_path,newpath);    /* let globals know */
  1315. X        strcpy(path,newpath);
  1316. X        cur_entry = first_visible = 0;
  1317. X        state = ILS_INITIAL;        /* make this the active one */
  1318. X        next_state = ILS_FIND_CURSOR;
  1319. X        break;
  1320. X        case ILS_EXIT:            /* QUIT! */
  1321. X        move(last_y,last_x);
  1322. X        addch(' ');            /* erase cursor */
  1323. X        level--;            /* back up one level */
  1324. X        if(level==0) {
  1325. X            noraw();
  1326. X            echo();
  1327. X        }
  1328. X        return(1);
  1329. X        break;
  1330. X          }
  1331. X    }
  1332. X}
  1333. X
  1334. X/* add an entry to a directory list.
  1335. X** pattern is the array of search patterns as passed to ils()
  1336. X** i is the inode number of this entry
  1337. X** p is the name of this entry
  1338. X** place the the pointer to the directory list (of d_entry's)
  1339. X*/
  1340. add_entry(pattern,i,p,place)
  1341. long    i;
  1342. char    *pattern[],*p;
  1343. struct    d_entry **place;
  1344. X{
  1345. X    struct    d_entry    *t, *cur, *last;
  1346. X    int    l, match;
  1347. X    struct    stat    st;
  1348. X    char    *ps, *pd;
  1349. X
  1350. X    if(i==0)        /* if inode is 0, file was removed */
  1351. X        return;
  1352. X    if(stat(p,&st)<0)    /* can't stat file, don't add it */
  1353. X        return;
  1354. X    if(p[0]=='.' && (modes&ILS_ALL)==0) /* is this a "." file? */
  1355. X        return;        /* starts with '.', not in list all mode */
  1356. X    if(pattern[0]!=(char *)NULL) {    /* if patterns are used, see if match */
  1357. X        for(l=match=0;pattern[l]!=(char *)NULL && match==0;l++) {
  1358. X            if(wildmat(p,pattern[l]))
  1359. X                match++;    /* matches a pattern */
  1360. X        }
  1361. X        if(!match)
  1362. X            return;        /* doesn't match any patterns */
  1363. X    }
  1364. X    
  1365. X    new_entry(&t,p,&st);        /* get memory and assign values */
  1366. X
  1367. X    if(*place == (struct d_entry *)NULL)     /* empty list */
  1368. X        *place=t;
  1369. X    else {
  1370. X        /* loop through and decide where to place the new entry.
  1371. X           the list is a sorted doubly-linked list. */
  1372. X        cur = last = *place;
  1373. X        while(cur != (struct d_entry *)NULL) {
  1374. X            if(strcmp(p,cur->name) < 0) {    /* insert before */
  1375. X                if(cur == *place) {    /* at top of list */
  1376. X                    t->next = *place;
  1377. X                    cur->prev = t;
  1378. X                    *place = t;
  1379. X                    return;
  1380. X                }
  1381. X                else {            /* in middle */
  1382. X                    cur->prev->next = t;
  1383. X                    t->prev = cur->prev;
  1384. X                    cur->prev = t;
  1385. X                    t->next = cur;
  1386. X                    return;
  1387. X                }
  1388. X            }
  1389. X            else {        /* check next name */
  1390. X                last = cur;
  1391. X                cur = cur->next;
  1392. X            }
  1393. X        }
  1394. X        if( cur == (struct d_entry *)NULL) { /* insert at end of list */
  1395. X            last->next = t;
  1396. X            t->prev = last;
  1397. X        }
  1398. X    }
  1399. X}
  1400. X
  1401. X/* get a string from the keyboard, and process it based on defined keysequences.
  1402. X** c is the first character (as entered in the mailine ils code above.
  1403. X**    if c is not a FORCE_KEYBOARD character, thenn it is inserted into
  1404. X**    the string passed to the string editing routine, as the first character
  1405. X**    of the user's string.
  1406. X** leftx,upy,rightx,downy are screen coordinates of the window size,
  1407. X**    regarding the location of the upper-left and lower-right corners.
  1408. X** line    is a pointer to a string.  This is where the keyboard input will
  1409. X**    be placed and thus passed back to the calling routine.
  1410. X*/ 
  1411. keybd(c,leftx,upy,rightx,downy,line)
  1412. int    leftx, upy, rightx, downy;
  1413. char    c, line[];
  1414. X{
  1415. X    int    l;
  1416. X
  1417. X    if(c==ILS_FORCE_KEYBOARD)    /* is this a FORCED KEY SEQUENCE? */
  1418. X        line[0]='\0';
  1419. X    else {            /* if legal character, insert into line[] */
  1420. X        if(c<' ' || c >0x7f)    /* out of range */
  1421. X            return;
  1422. X        line[0]=c;
  1423. X        line[1]='\0';
  1424. X    }
  1425. X
  1426. X    if(rightx-leftx-7 < 2)        /* see if we can fit the prompt */
  1427. X        return(0);        /* no space on screen for input */
  1428. X    move(upy,leftx);
  1429. X    printw("Input: ");        /* print the prompt */
  1430. X    l=getst(rightx-leftx-8,leftx+7,upy,line,rightx-leftx-7,&l,ALL_ALPHA,NULL);
  1431. X    if(l==GET_RETURN || l==GET_DOWN)
  1432. X        return(1);
  1433. X    return(0);    /* probably ESCAPED out */
  1434. X}
  1435. X
  1436. X/* free_contents() de-allocates the contents of the directory pointed at 
  1437. X** by p.
  1438. X*/
  1439. free_contents(p)
  1440. struct    d_entry    *p;
  1441. X{
  1442. X    if(p->next != (struct d_entry *)NULL)    /* depth-first deallaocation */
  1443. X        free_contents(p->next);
  1444. X    if(p->contents != (struct d_entry *)NULL) /* get rid of contents */
  1445. X        free_contents(p->contents);
  1446. X    free(p);                /* get rid of top node */
  1447. X}
  1448. X
  1449. X/* re_read_dir() takes another look at the contents of a directory for
  1450. X** changes in the contents or mode bits of the directory members.
  1451. X** This is used when a directory is re-entered into, and we need to see
  1452. X** if files were remove, added, or changed in any way.
  1453. X** 
  1454. X** pattern is the array of search patterns as passed to ils() initially.
  1455. X**
  1456. X** dptr is the pointer to the contents of the directory last time it was
  1457. X** examined.
  1458. X*/
  1459. re_read_dir(pattern,dptr)
  1460. char    *pattern[];
  1461. struct    d_entry    **dptr;
  1462. X{
  1463. X    char    name[MAXPATH], *pd, *ps;
  1464. X    struct    d_entry    *tdptr,*t;
  1465. X    int    i,inode,r,done,mxloop;
  1466. X    struct    stat    st;
  1467. X    long    touch, time();
  1468. X#ifdef BSD        /* berkeley directories are different */
  1469. X    DIR    *dp, *opendir();
  1470. X    struct    direct    *dirptr, *readdir();
  1471. X
  1472. X    if(chdir(cur_path)<0)
  1473. X        return;
  1474. X    if((dp=opendir("."))==NULL)
  1475. X        return;
  1476. X    tdptr = *dptr;
  1477. X    touch = time((long *)0);
  1478. X    while((dirptr=readdir(dp))!=NULL) {
  1479. X        strcpy(name,dirptr->d_name);
  1480. X        inode = dirptr->d_fileno;
  1481. X#endif BSD
  1482. X
  1483. X#ifdef SYSTEMV
  1484. X    struct    direct    d;
  1485. X    int    fd;
  1486. X
  1487. X    if(chdir(cur_path)<0)
  1488. X        return;
  1489. X    if((fd=open(".",O_RDONLY))<0)
  1490. X        return;
  1491. X    tdptr = *dptr;
  1492. X    touch = time((long *)0);
  1493. X    while(read(fd,&d,sizeof(struct direct)) == sizeof(struct direct)) {
  1494. X        strncpy(name,d.d_name,DIRSIZ);
  1495. X        name[DIRSIZ]='\0';
  1496. X        inode = d.d_ino;
  1497. X#endif SYSTEMV
  1498. X        /* common entry-handling code */
  1499. X
  1500. X        if(inode)    /* if this file wasn't removed, stat it */
  1501. X            if(stat(name,&st)<0)
  1502. X            continue;    /* can't stat? forget this one! */
  1503. X        if(name[0]=='.' && (modes&ILS_ALL)==0)
  1504. X            continue;    /* skip this, not in 'list all' mode */
  1505. X        done=0;
  1506. X        mxloop=0;/* mxloop is a safeguard.  It was used for
  1507. X                initial debugging, and can probably be removed */
  1508. X        while(!done && mxloop++ < 10000) {
  1509. X            if((r=strcmp(name,tdptr->name))==0) {
  1510. X                if(inode) {    /* copy over new stat struct */
  1511. X                    for(i=0, ps=(char *)&st,pd=(char *)&(tdptr->stat);i<sizeof(struct stat);i++)
  1512. X                        *pd++ = *ps++;
  1513. X                    /* flag this file as "touched" */
  1514. X                    tdptr->touched = touch;
  1515. X                }
  1516. X                done=1;    /* file found, move on to next */
  1517. X            }
  1518. X            else if(r<0 && inode) {    /* name < tdptr->name insert before? */
  1519. X                if((tdptr->prev) == (struct d_entry *)NULL) {
  1520. X                    /* insert at top of list */
  1521. X                    new_entry(&t,name,&st);
  1522. X                    t->touched = touch;
  1523. X                    t->next = tdptr;
  1524. X                    tdptr->prev = t;
  1525. X                    *dptr = t;
  1526. X                    done=1;
  1527. X                }
  1528. X                else if(strcmp(name,tdptr->prev->name)>0) {
  1529. X                    /* insert above tdptr */
  1530. X                    new_entry(&t,name,&st);
  1531. X                    t->touched = touch;
  1532. X                    tdptr->prev->next = t;
  1533. X                    t->next = tdptr;
  1534. X                    t->prev = tdptr->prev;
  1535. X                    tdptr->prev = t;
  1536. X                    done=1;
  1537. X                }
  1538. X                else
  1539. X                    tdptr = tdptr->prev;
  1540. X            }
  1541. X            else if(inode) { /* name > tdptr->name  insert after? */
  1542. X                if((tdptr->next) == (struct d_entry *)NULL) {
  1543. X                    /* insert at end of list */
  1544. X                    new_entry(&t,name,&st);
  1545. X                    t->touched = touch;
  1546. X                    tdptr->next = t;
  1547. X                    t->prev = tdptr;
  1548. X                    done=1;
  1549. X                }
  1550. X                else if(strcmp(name,tdptr->next->name)<0) {
  1551. X                    /* insert just below tdptr */
  1552. X                    new_entry(&t,name,&st);
  1553. X                    t->touched = touch;
  1554. X                    t->next = tdptr->next;
  1555. X                    tdptr->next = t;
  1556. X                    t->prev = tdptr;
  1557. X                    t->next->prev = t;
  1558. X                    done=1;
  1559. X                }
  1560. X                else
  1561. X                    tdptr = tdptr->next;
  1562. X            }
  1563. X            else
  1564. X                done=1;
  1565. X        }
  1566. X    }
  1567. X
  1568. X    /* loop through and remove all entries that have a different touch
  1569. X       if the touch value doesn't match, then file was removed and the
  1570. X       entry in the directory was used by a new filename. */
  1571. X    tdptr = *dptr;    /* start at top of directory */
  1572. X    while(tdptr != (struct d_entry *) NULL) {
  1573. X        if((tdptr->touched) != touch) {
  1574. X            /* need to remove this entry, see where it's at */
  1575. X            if(tdptr == (*dptr)) {
  1576. X                /* at the top */
  1577. X                *dptr = (*dptr)->next;
  1578. X                (*dptr)->prev = (struct d_entry *)NULL;
  1579. X                tdptr->next = (struct d_entry *)NULL;
  1580. X                free_contents(tdptr);
  1581. X                tdptr = *dptr;
  1582. X            }
  1583. X            else if(tdptr->next == (struct d_entry *)NULL) {
  1584. X                /* at the bottom */
  1585. X                tdptr->prev->next = (struct d_entry *)NULL;
  1586. X                free_contents(tdptr);
  1587. X                tdptr = (struct d_entry *) NULL;  /* end */
  1588. X            }
  1589. X            else {
  1590. X                /* in the middle somewhere */
  1591. X                t = tdptr->next;
  1592. X                tdptr->prev->next = tdptr->next;
  1593. X                tdptr->next->prev = tdptr->prev;
  1594. X                tdptr->next = (struct d_entry *) NULL;
  1595. X                free_contents(tdptr);
  1596. X                tdptr = t;
  1597. X            }
  1598. X        }
  1599. X        else    /* try next entry */
  1600. X            tdptr = tdptr->next;
  1601. X    }
  1602. X
  1603. X#ifdef BSD
  1604. X    closedir(dp);
  1605. X#endif BSD
  1606. X#ifdef SYSTEMV
  1607. X    close(fd);
  1608. X#endif SYSTEMV
  1609. X}
  1610. X
  1611. X/* new_entry allocates memory for a new addition to a directory, then
  1612. X** copies in the name and stat structure into the newly allocated structure.
  1613. X** It copies nulls into all of the structure's pointers.
  1614. X**
  1615. X** tex is to be assigned to the address of the new memory.
  1616. X** name is the string to copy into the name field.
  1617. X** st is a pointer to the stat structure to copy over.
  1618. X*/
  1619. new_entry(tex,name,st)
  1620. struct    d_entry    **tex;
  1621. char    *name;
  1622. struct    stat    *st;
  1623. X{
  1624. X    struct    d_entry    *t;
  1625. X    register int    i;
  1626. X    char    *pd, *ps;
  1627. X
  1628. X    if((*tex=t= (struct d_entry *) malloc(sizeof(struct d_entry)))==NULL) {
  1629. X        clear();
  1630. X        printw("OUT OF MEMORY!\n");
  1631. X        refresh();
  1632. X        ils_exit(1);
  1633. X    }
  1634. X    t->name = (char *)malloc(strlen(name)+1); /* alloc space for name */
  1635. X    strcpy(t->name,name);    /* copy name over */
  1636. X
  1637. X    for(i=0, ps=(char *)st,pd=(char *)&(t->stat);i<sizeof(struct stat);i++)
  1638. X        *pd++ = *ps++;    /* copy stat over on byte at a time */
  1639. X
  1640. X    t->next = (struct d_entry *) NULL;    /* null out all pointers */
  1641. X    t->prev = (struct d_entry *) NULL;
  1642. X    t->contents = (struct d_entry *) NULL;
  1643. X}
  1644. X
  1645. X/* exit ils gracefully with 'code' as the exit code */
  1646. ils_exit(code)
  1647. int    code;
  1648. X{
  1649. X    noraw();    /* out of raw mode */
  1650. X    echo();        /* echo back on */
  1651. X    endwin();    /* exit curses */
  1652. X    exit(code);
  1653. X}
  1654. END_OF_FILE
  1655. if test 25940 -ne `wc -c <'ils.c'`; then
  1656.     echo shar: \"'ils.c'\" unpacked with wrong size!
  1657. fi
  1658. # end of 'ils.c'
  1659. fi
  1660. if test -f 'ils.h' -a "${1}" != "-c" ; then 
  1661.   echo shar: Will not clobber existing file \"'ils.h'\"
  1662. else
  1663. echo shar: Extracting \"'ils.h'\" \(3354 characters\)
  1664. sed "s/^X//" >'ils.h' <<'END_OF_FILE'
  1665. X/* includes for ils program */
  1666. X#ifndef ushort
  1667. X#include    <sys/types.h>
  1668. X#endif
  1669. X
  1670. X#ifndef stat_h
  1671. X#include    <sys/stat.h>
  1672. X#endif
  1673. X
  1674. X#define ILS_MAX_ENTRIES        1000
  1675. X#define ILS_MAX_PATS        256    /* max search patterns */
  1676. X#define MAX_SYMBOLS        256    /* max symbol table size */
  1677. X
  1678. X/* types of display modes (can be ored if appropriate) */
  1679. X#define ILS_LONG    1    /* long format */
  1680. X#define ILS_ALL        8    /* list ALL files (even . and ..) */
  1681. X#define ILS_F_TYPE    0x10    /* directories end with '/', executables '*' */
  1682. X#define ILS_ECHO_COMS    0x20    /* echo commands as executed */
  1683. X
  1684. X#define ILS_ESCAPE    0x1b    /* hard-coded ESCAPE key */
  1685. X#define ILS_ENTER    '\n'    /* hard-coded RETURN oe ENTER key */
  1686. X#define ILS_RETURN    '\r'    /* hard-coded RETURN or ENTER key */
  1687. X#define ILS_DOWN    'j'    /* hard-coded DOWN */
  1688. X#define ILS_UP        'k'    /* hard-coded UP */
  1689. X#define ILS_LEFT    'h'    /* hard-coded LEFT */
  1690. X#define ILS_RIGHT    'l'    /* hard-coded RIGHT */
  1691. X#define ILS_REDRAW    18    /* control-r */
  1692. X#define ILS_REDRAW_ALT    12    /* control-l */
  1693. X#define ILS_ENV        '?'    /* display symbol table */
  1694. X#define ILS_FORCE_KEYBOARD ':'    /* force keyboard input */
  1695. X#define ILS_EXIT_KEY    4    /* control-d */
  1696. X
  1697. X#define ILS_FILE    ".ils"    /* ils definition file (per user) */
  1698. X
  1699. X#define ILS_INITIAL    -3    /* initial state (only done once) */
  1700. X#define ILS_INITIAL2    -2
  1701. X#define ILS_TOTAL_DRAW    -1    /* redraw path, title, and contents */
  1702. X#define ILS_DRAW    0    /* display directory content */
  1703. X#define ILS_KEYBOARD    1    /* get input from keyboard */
  1704. X#define ILS_MOVE_CURSOR 2    /* erase last cursor, show new */
  1705. X#define ILS_SHOW_CURSOR 3    /* redraw the cursor */
  1706. X#define ILS_EXIT    4    /* exit this level of edit_directory */
  1707. X#define ILS_SHOW_PATH    5    /* print the path on the top line */
  1708. X#define ILS_ASCEND    6    /* go up into a new directory */
  1709. X#define ILS_FIND_CURSOR 7    /* figure out best place to put cursor */
  1710. X
  1711. X#ifdef BSD
  1712. X#define flash() addch('\007')
  1713. X#endif
  1714. X
  1715. X#define ILS_METACHAR    '$'    /* Preceeds all ils variables */
  1716. X#define META1        '/'    /* List of sh metacharacters that can be used */
  1717. X#define META2        '<'    /* as delimeters. */
  1718. X#define META3        '>'
  1719. X#define META4        '('
  1720. X#define META5        ')'
  1721. X#define META6        '['
  1722. X#define META7        ']'
  1723. X#define META8        '&'
  1724. X#define META9        '|'
  1725. X#define META10        '`'
  1726. X#define META11        '\"'
  1727. X#define META12        '!'
  1728. X#define META13        '~'
  1729. X#define META14        '$'
  1730. X#define META15        '\''
  1731. X#define META16        '?'
  1732. X#define META17        ';'
  1733. X#define META18        '.'
  1734. X
  1735. X#define ILS_MAX_ARGS    256    /* max arguments per single command line */
  1736. X#define MAXPATH        128
  1737. X#define PWD        "/bin/pwd"
  1738. X
  1739. X#define BOTTOM    0
  1740. X#define TOP    1
  1741. X
  1742. typedef struct d_entry {
  1743. X    char    *name;
  1744. X    int    inode;
  1745. X    struct    stat    stat;        /* stat for this file touched */
  1746. X    struct    d_entry *next;        /* next entry in this directory */
  1747. X    struct    d_entry *prev;        /* previous entry in this directory */
  1748. X    struct    d_entry *contents;    /* if a directory, it's contents */
  1749. X    long    touched;        /* flag for last time touched */
  1750. X};
  1751. X
  1752. typedef struct    value {
  1753. X    char    *v;
  1754. X    struct    value    *next;
  1755. X};
  1756. X
  1757. X#define ILS_KEY_SEQUENCE    1
  1758. X#define ILS_VARIABLE        2
  1759. X
  1760. typedef    struct    symbol {
  1761. X    char    *name;            /* name of this symbol */
  1762. X    int    type;            /* symbol type */
  1763. X    struct    value    *val;        /* pointer to symbol value */
  1764. X};
  1765. X
  1766. X#define CURRENT_FILE    "file"        /* insert this file */
  1767. X#define ALL_FILES    "all_files"    /* insert all files in directory */
  1768. X#define INPUT        "input"        /* input from keyboard command */
  1769. X#define PREFIX        "prefix"    /* insert the prefix (before .) */
  1770. X#define PWD_PATH    "path"        /* insert the path (ala `pwd`) */
  1771. END_OF_FILE
  1772. if test 3354 -ne `wc -c <'ils.h'`; then
  1773.     echo shar: \"'ils.h'\" unpacked with wrong size!
  1774. fi
  1775. # end of 'ils.h'
  1776. fi
  1777. if test -f 'input.c' -a "${1}" != "-c" ; then 
  1778.   echo shar: Will not clobber existing file \"'input.c'\"
  1779. else
  1780. echo shar: Extracting \"'input.c'\" \(5006 characters\)
  1781. sed "s/^X//" >'input.c' <<'END_OF_FILE'
  1782. X#include    <curses.h>
  1783. X#include    "ils.h"
  1784. X#include    "get.h"
  1785. X
  1786. extern    int    syms;    /* number of symbols on symbol table */
  1787. extern    struct    symbol    *symtab[];
  1788. extern    char    *pnam;
  1789. extern    int    a_num;    /* number of arguments in list */
  1790. extern    int    a_ind;    /* index into current argument */
  1791. extern    char    *args[ILS_MAX_ARGS];
  1792. extern    char    cur_path[];        /* pointer to active path */
  1793. extern    int    modes;    /* what special flags might be set */
  1794. X
  1795. process_input(c,list,entry,entries,p,x,y,rx)
  1796. struct    d_entry    *list[];
  1797. int    entry, entries,x,y,rx;
  1798. char    p[],c;
  1799. X{
  1800. X    struct    value    *v;
  1801. X    char    line[256];
  1802. X
  1803. X    int    i=0;
  1804. X
  1805. X    if(c==ILS_FORCE_KEYBOARD) {
  1806. X        evaluate_line(line,p,list,entry,entries,x,y,rx);
  1807. X        ils_doit(line);        /* execute the statement */
  1808. X    }
  1809. X    else {
  1810. X        for(i=0;i<syms;i++)
  1811. X            if(strcmp(symtab[i]->name,p)==0){/* found the command */
  1812. X                perform_command(!c,symtab[i]->val,list,entry,entries,x,y,rx);
  1813. X                break;        /* get out of loop */
  1814. X            }
  1815. X        if(i==syms)
  1816. X            flash();
  1817. X    }
  1818. X}
  1819. X
  1820. perform_command(c,v,list,entry,entries,x,y,rx)
  1821. struct    value    *v;
  1822. struct    d_entry    *list[];
  1823. int    entry, entries,x,y,rx;
  1824. X{
  1825. X    char    line[256];
  1826. X    int    i;
  1827. X
  1828. X    while(v != (struct value *) NULL) {
  1829. X        evaluate_line(line,v->v,list,entry,entries,x,y,rx);
  1830. X        ils_doit(line);        /* execute the statement */
  1831. X        v = v->next;
  1832. X    }
  1833. X    dealloc(args);
  1834. X}
  1835. X
  1836. ils_doit(line)
  1837. char    *line;
  1838. X{
  1839. X    noraw();
  1840. X    echo();
  1841. X    clear();
  1842. X    if(modes & ILS_ECHO_COMS)
  1843. X        printw("%s\n",line);
  1844. X    refresh();
  1845. X#ifdef BSD
  1846. X    endwin();
  1847. X#endif
  1848. X
  1849. X    system(line);        /* execute the statement */
  1850. X#ifdef BSD
  1851. X    printf("PRESS RETURN TO RETURN TO %s\n",pnam);
  1852. X    getchar();
  1853. X    initscr();
  1854. X    scrollok(stdscr,TRUE);
  1855. X    raw();
  1856. X    noecho();
  1857. X#endif
  1858. X
  1859. X#ifdef SYSTEMV
  1860. X    raw();
  1861. X    noecho();
  1862. X    standout();
  1863. X    printw("Press any key to return to %s",pnam);
  1864. X    standend();
  1865. X    refresh();
  1866. X    getch();
  1867. X#endif SYSTEMV
  1868. X}    
  1869. X
  1870. evaluate_line(line,s,list,entry,entries,x,y,rx)
  1871. char    s[], line[];
  1872. struct    d_entry    *list[];
  1873. int    entry, entries,x,y,rx;
  1874. X{
  1875. X    char        c, lable[160], arg[160], new_line[256];
  1876. X    register    int    k;
  1877. X    int        l, a=0, j, white=0, d, ln=0, i, line_ind=0;
  1878. X
  1879. X    l = strlen(s);
  1880. X    for(i=0;i<l;i++) {
  1881. X        switch(c=s[i]) {
  1882. X            case ILS_METACHAR:
  1883. X                i++;
  1884. X                for(k=d=0;i<l && d==0;i++) {
  1885. X                    switch(c=s[i]) {
  1886. X                        case META1:  /* possible delimeters */    
  1887. X                        case META2:    
  1888. X                        case META3:    
  1889. X                        case META4:    
  1890. X                        case META5:    
  1891. X                        case META6:    
  1892. X                        case META7:    
  1893. X                        case META8:    
  1894. X                        case META9:    
  1895. X                        case META10:    
  1896. X                        case META11:    
  1897. X                        case META12:    
  1898. X                        case META13:    
  1899. X                        case META14:    
  1900. X                        case META15:    
  1901. X                        case META16:    
  1902. X                        case META17:    
  1903. X                        case META18:    
  1904. X                        case ' ':
  1905. X                        case '\T':
  1906. X                            i--;
  1907. X                            d=1;
  1908. X                            break;
  1909. X                        default:
  1910. X                            lable[k++]=c;
  1911. X                            break;
  1912. X                    }
  1913. X                }
  1914. X                lable[k]='\0';
  1915. X                insert_value(new_line,lable,list,entry,entries,s,&i,x,y,rx);
  1916. X                i--;
  1917. X                for(j=0;new_line[j]!='\0';j++,line_ind++)
  1918. X                    line[line_ind] = new_line[j];
  1919. X                white=0;
  1920. X                break;
  1921. X            case ' ':
  1922. X            case '\t':
  1923. X                if(white)
  1924. X                    break;
  1925. X                white=1;
  1926. X                line[line_ind++]=' ';
  1927. X                break;
  1928. X            default:
  1929. X                white=0;
  1930. X                line[line_ind++]=c;
  1931. X                break;
  1932. X        }
  1933. X    }
  1934. X    line[line_ind]='\0';
  1935. X}
  1936. X
  1937. dealloc(args)
  1938. char    *args[];
  1939. X{
  1940. X    register int    i;
  1941. X
  1942. X    for(i=0;i<ILS_MAX_ARGS && args[i]!=(char *)NULL;i++)
  1943. X        free(args[i]);
  1944. X}
  1945. X
  1946. insert_value(line,lable,list,entry,entries,s,ii,x,y,rx)
  1947. char    line[],lable[], s[];
  1948. int    *ii,x,y,rx;
  1949. struct    d_entry    *list[];
  1950. int    entry, entries;
  1951. X{
  1952. X    char    *c, prompt[256], new_prompt[256];
  1953. X    register    int    i, parens, k;
  1954. X    int    l;
  1955. X
  1956. X    if(strcmp(lable,CURRENT_FILE)==0)
  1957. X        strcpy(line,list[entry]->name);
  1958. X    else if(strcmp(lable,PREFIX)==0) {
  1959. X        for(i=0;i<strlen(list[entry]->name) && list[entry]->name[i]!='.';i++)
  1960. X            line[i] = list[entry]->name[i];
  1961. X        line[i]='\0';
  1962. X    }
  1963. X    else if(strcmp(lable,PWD_PATH)==0) {
  1964. X        for(i=0;cur_path[i]!='\0';i++)
  1965. X            line[i] = cur_path[i];
  1966. X        line[i]='\0';
  1967. X    }
  1968. X    else if(strcmp(lable,INPUT)==0) {
  1969. X        (*ii)++;
  1970. X        for(parens=1,k=0;parens && s[*ii]!='\0';(*ii)++)
  1971. X            switch(s[*ii]) {
  1972. X                case ')':
  1973. X                    parens--;
  1974. X                    if(parens)
  1975. X                        prompt[k++]=s[*ii];
  1976. X                    break;
  1977. X                case '(':
  1978. X                    parens++;
  1979. X                default:
  1980. X                    prompt[k++]=s[*ii];
  1981. X                    break;
  1982. X            }
  1983. X        if(parens)
  1984. X            return(1);
  1985. X        prompt[k]='\0';
  1986. X
  1987. X        move(y,x);
  1988. X        
  1989. X        evaluate_line(new_prompt,prompt,list,entry,entries,x,y,rx);
  1990. X        l=strlen(new_prompt);
  1991. X        printw(new_prompt);
  1992. X        line[0]='\0';
  1993. X        if(getst(rx-x-l-1,x+l,y,line,rx-x-l,&l,ALL_ALPHA,NULL)!=GET_RETURN)
  1994. X            return(1);
  1995. X    }
  1996. X#ifdef SYSTEMV
  1997. X    else if((c=(char *)getenv(lable))!=NULL)
  1998. X        strcpy(line,c);
  1999. X#endif SYSTEMV
  2000. X}
  2001. X
  2002. X/* add to the argument list */
  2003. X/* c is for passing a single character, str is for passing a string,
  2004. X * type==0 for char, 1 for string */
  2005. add_to_args(c,str,type)
  2006. char    c, str[];
  2007. int    type;
  2008. X{
  2009. X    int    l,i;
  2010. X
  2011. X    if(type) {
  2012. X        l=strlen(str);
  2013. X        for(i=0;i<l;i++)
  2014. X            add_char_to_args(str[i]);
  2015. X    }
  2016. X    else
  2017. X        add_char_to_args(c);
  2018. X}
  2019. X
  2020. add_char_to_args(c)
  2021. char    c;
  2022. X{
  2023. X    static    char    line[256];
  2024. X    static    int    line_ind=0;
  2025. X
  2026. X    switch(c) {
  2027. X        case ' ':
  2028. X        case '\t':
  2029. X            line[line_ind]='\0';
  2030. X            args[a_num] = (char *) malloc(strlen(line)+1);
  2031. X            strcpy(args[a_num],line);
  2032. X            a_num++;
  2033. X            a_ind=0;
  2034. X            line_ind=0;
  2035. X            break;
  2036. X        default:
  2037. X            line[line_ind++]=c;
  2038. X            if(line_ind>254)
  2039. X                line_ind=254;
  2040. X            break;
  2041. X    }
  2042. X}
  2043. END_OF_FILE
  2044. if test 5006 -ne `wc -c <'input.c'`; then
  2045.     echo shar: \"'input.c'\" unpacked with wrong size!
  2046. fi
  2047. # end of 'input.c'
  2048. fi
  2049. if test -f 'main.c' -a "${1}" != "-c" ; then 
  2050.   echo shar: Will not clobber existing file \"'main.c'\"
  2051. else
  2052. echo shar: Extracting \"'main.c'\" \(2923 characters\)
  2053. sed "s/^X//" >'main.c' <<'END_OF_FILE'
  2054. X/**************************************************************************
  2055. X** main() routine for ils.
  2056. X**
  2057. X** ils (c) copyright 1991 by Jack Alexander
  2058. X**
  2059. X** NO WARRANTY OF ANY KIND IS ASSOCIATED WITH THIS PROGRAM, NOT EVEN
  2060. X** FOR FITNESS OF PURPOSE
  2061. X**
  2062. X**/
  2063. X#include    <curses.h>
  2064. X#include    <stdio.h>
  2065. X#include    "ils.h"
  2066. X
  2067. char    *pnam;
  2068. char    *patterns[ILS_MAX_PATS];
  2069. X
  2070. main(argc,argv)
  2071. int    argc;
  2072. char    *argv[];
  2073. X{
  2074. X    int    rows=0, cols=0, i, j, pats, modes=0,errs=0,skip,l;
  2075. X    char    curdir[MAXPATH], *title, c;
  2076. X
  2077. X    pnam = argv[0];        /* globnal pointer to program name */
  2078. X    title = (char *) NULL;    /* no title, yet */
  2079. X
  2080. X    /* extract any modes that may be part of a default dure to filename */
  2081. X    switch(argv[0][strlen(argv[0])-1]) {
  2082. X        case 'a':
  2083. X            modes |= ILS_ALL;
  2084. X            break;
  2085. X        case 'f':
  2086. X            modes |= ILS_F_TYPE;
  2087. X            break;
  2088. X        case 'l':
  2089. X            modes |= ILS_LONG;
  2090. X            break;
  2091. X    }
  2092. X    for(i=1,pats=0;i<argc;i++) {    /* look at all arguments passed */
  2093. X        skip=0;
  2094. X        switch(argv[i][0]) {
  2095. X            case '-':    /* handle the option */
  2096. X                l = strlen(argv[i]);
  2097. X                for(j=1;j<l;j++) {
  2098. X                    switch(argv[i][j]) {
  2099. X                        case 'r':
  2100. X                        /* change number of rows */
  2101. X                            j++;
  2102. X                            c = argv[i][j];
  2103. X                            while(c>='0' && c<='9' && j<l) {
  2104. X                                rows *= 10;
  2105. X                                rows += c-'0';
  2106. X                                j++;
  2107. X                                c = argv[i][j];
  2108. X                            }
  2109. X                            j--;
  2110. X                            break;
  2111. X                        case 'c':
  2112. X                        /* change number of columns */
  2113. X                            j++;
  2114. X                            c = argv[i][j];
  2115. X                            while(c>='0' && c<='9' && j<l) {
  2116. X                                cols *= 10;
  2117. X                                cols += c-'0';
  2118. X                                j++;
  2119. X                                c = argv[i][j];
  2120. X                            }
  2121. X                            j--;
  2122. X                            break;
  2123. X                        case 'a':
  2124. X                        /* list ALL mode (. files) */
  2125. X                            modes |= ILS_ALL;
  2126. X                            break;
  2127. X                        case 'F':
  2128. X                        /* show * and / */
  2129. X                            modes |= ILS_F_TYPE;
  2130. X                            break;
  2131. X                        case 'l':
  2132. X                        /* long listing format */
  2133. X                            modes |= ILS_LONG;
  2134. X                            break;
  2135. X                        case 'e':
  2136. X                        /* echo commands */
  2137. X                            modes |= ILS_ECHO_COMS;
  2138. X                            break;
  2139. X                        case 'T':
  2140. X                        /* window to have title */
  2141. X                            if((i+1)>=argc) {
  2142. X                                fprintf(stderr,"%s: -T option must be followed with a title\n",pnam);
  2143. X                                fprintf(stderr,"    example: %s -T \"This is a title\"\n",pnam);
  2144. X                                errs++;
  2145. X                            }
  2146. X                            else {
  2147. X                                title = argv[i+1];
  2148. X                                skip=1;
  2149. X                            }
  2150. X                            break;
  2151. X                    }
  2152. X                }
  2153. X                break;
  2154. X            default:
  2155. X                patterns[pats++] = argv[i];
  2156. X        }
  2157. X        i+=skip;
  2158. X        skip=0;
  2159. X    }
  2160. X    if(errs) {
  2161. X        fprintf(stderr,"%s: errors in parameters\n",pnam);
  2162. X        exit(0);
  2163. X    }
  2164. X    patterns[pats] = (char *) NULL;
  2165. X
  2166. X    initscr();        /* init curses */
  2167. X    scrollok(stdscr,TRUE);
  2168. X    if(!rows)
  2169. X        rows = LINES;
  2170. X    if(!cols)
  2171. X        cols = COLS;
  2172. X
  2173. X    if(get_curdir(curdir)) {
  2174. X        endwin();
  2175. X        exit(0);
  2176. X    }
  2177. X    ils(patterns,curdir,0,0,cols,rows,modes,title);
  2178. X#ifdef BSD
  2179. X    clear();
  2180. X    printw("Leaving %s...\n",pnam);
  2181. X    refresh();
  2182. X#endif
  2183. X    endwin();        /* end curses */
  2184. X}
  2185. X
  2186. get_curdir(path)
  2187. char    path[];
  2188. X{
  2189. X    FILE    *fp;
  2190. X
  2191. X    if((fp=popen(PWD,"r"))==NULL) {
  2192. X        fprintf(stderr,"%s: popen returns error\n",pnam);
  2193. X        return(1);
  2194. X    };
  2195. X    fscanf(fp,"%s",path);
  2196. X    pclose(fp);
  2197. X    return(0);
  2198. X}
  2199. END_OF_FILE
  2200. if test 2923 -ne `wc -c <'main.c'`; then
  2201.     echo shar: \"'main.c'\" unpacked with wrong size!
  2202. fi
  2203. # end of 'main.c'
  2204. fi
  2205. if test -f 'parse.c' -a "${1}" != "-c" ; then 
  2206.   echo shar: Will not clobber existing file \"'parse.c'\"
  2207. else
  2208. echo shar: Extracting \"'parse.c'\" \(3638 characters\)
  2209. sed "s/^X//" >'parse.c' <<'END_OF_FILE'
  2210. X#include    <stdio.h>
  2211. X#include    <curses.h>
  2212. X#include    "ils.h"
  2213. X
  2214. X#define NUETRAL        0    /* states used in parse */
  2215. X#define IN_OP        1
  2216. X
  2217. extern    char    *pnam;            /* program name */
  2218. extern    struct    symbol    *symtab[];    /* symbol table */
  2219. extern    int    syms;            /* number of symbols on table */
  2220. X
  2221. parse_line(line,lnum)
  2222. char    line[];
  2223. int    lnum;
  2224. X{
  2225. X    static    int    state=NUETRAL,o,no;
  2226. X    char    ops[2][160];
  2227. X
  2228. X    o=get_opts(ops,line);    /* Get the 2 possible parts */
  2229. X
  2230. X    if(!o)
  2231. X        return(0);        /* line was just white space */
  2232. X    switch(state) {
  2233. X        case NUETRAL:
  2234. X            if(o==1) {
  2235. X                printw("%s: error on line %d of '%s' file\n",pnam,lnum,ILS_FILE);
  2236. X                refresh();
  2237. X                return(1);
  2238. X            }
  2239. X            no=new_op(ops,ILS_KEY_SEQUENCE);
  2240. X            state=IN_OP;
  2241. X            break;
  2242. X        case IN_OP:
  2243. X            if(o==2)
  2244. X                no=new_op(ops,ILS_KEY_SEQUENCE);
  2245. X            else
  2246. X                add_op(no,ops);
  2247. X            break;
  2248. X        default:
  2249. X            printw("%s: bad state in parse_line()\n",pnam);
  2250. X            refresh();
  2251. X            return(1);
  2252. X            break;
  2253. X    }
  2254. X    return(0);
  2255. X}
  2256. X
  2257. X#define ESC        1
  2258. X#define COLON        2
  2259. X#define NEWLINE        3
  2260. X#define SKIP_WHITE    4
  2261. X
  2262. get_opts(s,line)
  2263. char    s[2][160], line[];
  2264. X{
  2265. X    int    i,j,k,l,nonwhite=0,state=0,colons=0;
  2266. X    char    c;
  2267. X
  2268. X    l=strlen(line);
  2269. X    s[0][0]=s[1][0]='\0';
  2270. X
  2271. X    for(i=j=k=0;i<l;i++) {
  2272. X        switch(c=line[i]){
  2273. X            case '\\':
  2274. X                state=ESC;
  2275. X                continue;
  2276. X            case '\n':
  2277. X                state=NEWLINE;
  2278. X                break;
  2279. X            case ':':
  2280. X                state=COLON;
  2281. X                colons++;
  2282. X                if(colons==1)
  2283. X                    break;
  2284. X                else
  2285. X                    state=0;
  2286. X            default:
  2287. X                if(c==' '||c=='\t')
  2288. X                    break;
  2289. X                nonwhite=1;
  2290. X                break;
  2291. X        }
  2292. X        switch(state) {
  2293. X            case ESC:
  2294. X                s[j][k]=c;
  2295. X                break;
  2296. X            case COLON:
  2297. X                s[j][k]='\0';
  2298. X                j=1;
  2299. X                k=0;
  2300. X                state=SKIP_WHITE;
  2301. X                break;
  2302. X            case NEWLINE:
  2303. X                s[j][k]='\0';
  2304. X                k=0;
  2305. X                break;
  2306. X            case SKIP_WHITE:
  2307. X                if(c==' '||c=='\t')
  2308. X                    break;
  2309. X                else
  2310. X                    state=0;
  2311. X            default:
  2312. X                if(!nonwhite)    /* skip leading white space */
  2313. X                    continue;
  2314. X                s[j][k++]=c;
  2315. X                break;
  2316. X        }
  2317. X    }
  2318. X    if(nonwhite)
  2319. X        return(j+1);    /* j=0 if one field, j=1 if two fields */
  2320. X    else
  2321. X        return(0);    /* line was all white space */
  2322. X}
  2323. X
  2324. new_op(s,type)
  2325. char    s[2][160];
  2326. int    type;
  2327. X{
  2328. X    struct    symbol    *t;
  2329. X    struct    value    *v;
  2330. X
  2331. X    if(syms==MAX_SYMBOLS) {
  2332. X        fprintf(stderr,"%s: symbol table size exceeded\n",pnam);
  2333. X        return;
  2334. X    }
  2335. X    t = symtab[syms] = (struct symbol *) malloc(sizeof(struct d_entry));
  2336. X    if(t == NULL) {
  2337. X        fprintf(stderr,"%s: out of memory\n",pnam);
  2338. X        return;
  2339. X    }
  2340. X    t->name = (char *)malloc(strlen(s[0])+1);
  2341. X    strcpy(t->name,s[0]);
  2342. X    t->type = type;
  2343. X
  2344. X    if(s[1][0]=='\0')
  2345. X        t->val = (struct value *)NULL;
  2346. X    else {
  2347. X        v = t->val = (struct value *) malloc(sizeof(struct value));
  2348. X        v->v = (char *)malloc(strlen(s[1])+1);
  2349. X        strcpy(v->v,s[1]);
  2350. X        v->next =(struct value *) NULL;
  2351. X    }
  2352. X
  2353. X    return(syms++);
  2354. X}
  2355. X
  2356. add_op(op,s)
  2357. int    op;
  2358. char    s[2][160];
  2359. X{
  2360. X    struct    value    *v;
  2361. X
  2362. X    v = symtab[op]->val;
  2363. X    
  2364. X    if(v==(struct value *)NULL) {
  2365. X        v = symtab[op]->val = (struct value *) malloc(sizeof(struct value));
  2366. X        v->next =(struct value *) NULL;
  2367. X    }
  2368. X    else {
  2369. X        while(v->next != (struct value *)NULL)
  2370. X            v = v->next;
  2371. X        v->next = (struct value *) malloc(sizeof(struct value));
  2372. X        v->next->next = (struct value *) NULL;
  2373. X        v = v->next;
  2374. X    }
  2375. X    v->v = (char *)malloc(strlen(s[0])+1);
  2376. X    strcpy(v->v,s[0]);
  2377. X}
  2378. X
  2379. display_symtab()
  2380. X{
  2381. X    int    i, over=0;
  2382. X    struct    value    *v;
  2383. X
  2384. X    for(i=0;i<syms;i++) {
  2385. X        clear();
  2386. X        standout();
  2387. X        printw("Symbol %d: %s\n",i+1,symtab[i]->name);
  2388. X        standend();
  2389. X        v = symtab[i]->val;
  2390. X        while(v!=NULL && over++ != MAX_SYMBOLS) {
  2391. X            printw("    %s\n",v->v);
  2392. X            v = v->next;
  2393. X        }
  2394. X        standout();
  2395. X        printw("Press RETURN next symbol, %c for previous, ESC to exit",
  2396. X            ILS_LEFT);
  2397. X        standend();
  2398. X        refresh();
  2399. X        switch(getch()&0x7f) {
  2400. X            case ILS_ENTER:
  2401. X            case ILS_RETURN:
  2402. X                break;
  2403. X            case ILS_LEFT:
  2404. X                if(i!=0)
  2405. X                    i -= 2;
  2406. X                else
  2407. X                    i--;
  2408. X                break;
  2409. X            case ILS_ESCAPE:
  2410. X                return;
  2411. X        }
  2412. X    }
  2413. X}
  2414. END_OF_FILE
  2415. if test 3638 -ne `wc -c <'parse.c'`; then
  2416.     echo shar: \"'parse.c'\" unpacked with wrong size!
  2417. fi
  2418. # end of 'parse.c'
  2419. fi
  2420. if test -f 'wildmat.c' -a "${1}" != "-c" ; then 
  2421.   echo shar: Will not clobber existing file \"'wildmat.c'\"
  2422. else
  2423. echo shar: Extracting \"'wildmat.c'\" \(2677 characters\)
  2424. sed "s/^X//" >'wildmat.c' <<'END_OF_FILE'
  2425. X/*
  2426. X**  Do shell-style pattern matching for ?, \, [], and * characters.
  2427. X**  Might not be robust in face of malformed patterns; e.g., "foo[a-"
  2428. X**  could cause a segmentation violation.  It is 8bit clean.
  2429. X**
  2430. X**  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
  2431. X**  Special thanks to Lars Mathiesen for the ABORT code.  This can greatly
  2432. X**  speed up failing wildcard patterns.  For example:
  2433. X**    pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
  2434. X**    text 1:     -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
  2435. X**    text 2:     -adobe-courier-bold-o-normal--12-120-75-75-p-70-iso8859-1
  2436. X**  Text 1 matches with 51 calls, while text 2 fails with 54 calls.  Without
  2437. X**  the ABORT, then it takes 22310 calls to fail.  Ugh.
  2438. X*/
  2439. X
  2440. X#define TRUE        1
  2441. X#define FALSE        0
  2442. X#define ABORT        -1
  2443. X
  2444. static int
  2445. Star(s, p)
  2446. X    register char    *s;
  2447. X    register char    *p;
  2448. X{
  2449. X    while (wildmat(s, p) == FALSE)
  2450. X    if (*++s == '\0')
  2451. X        return ABORT;
  2452. X    return TRUE;
  2453. X}
  2454. X
  2455. X
  2456. static int
  2457. DoMatch(s, p)
  2458. X    register char    *s;
  2459. X    register char    *p;
  2460. X{
  2461. X    register int      last;
  2462. X    register int      matched;
  2463. X    register int      reverse;
  2464. X
  2465. X    for ( ; *p; s++, p++) {
  2466. X    if (*s == '\0')
  2467. X        return ABORT;
  2468. X    switch (*p) {
  2469. X    case '\\':
  2470. X        /* Literal match with following character. */
  2471. X        p++;
  2472. X        /* FALLTHROUGH */
  2473. X    default:
  2474. X        if (*s != *p)
  2475. X        return FALSE;
  2476. X        continue;
  2477. X    case '?':
  2478. X        /* Match anything. */
  2479. X        continue;
  2480. X    case '*':
  2481. X        /* Trailing star matches everything. */
  2482. X        return *++p ? Star(s, p) : TRUE;
  2483. X    case '[':
  2484. X        /* [^....] means inverse character class. */
  2485. X        if (reverse = p[1] == '^')
  2486. X        p++;
  2487. X        for (last = 0400, matched = FALSE; *++p && *p != ']'; last = *p)
  2488. X        /* This next line requires a good C compiler. */
  2489. X        if (*p == '-' ? *s <= *++p && *s >= last : *s == *p)
  2490. X            matched = TRUE;
  2491. X        if (matched == reverse)
  2492. X        return FALSE;
  2493. X        continue;
  2494. X    }
  2495. X    }
  2496. X
  2497. X    return *s == '\0';
  2498. X}
  2499. X
  2500. X
  2501. int
  2502. wildmat(s, p)
  2503. X    char    *s;
  2504. X    char    *p;
  2505. X{
  2506. X    return DoMatch(s, p) == TRUE;
  2507. X}
  2508. X
  2509. X
  2510. X
  2511. X#ifdef    TEST
  2512. X#include <stdio.h>
  2513. X
  2514. X/* Yes, we use gets not fgets.  Sue me. */
  2515. extern char    *gets();
  2516. X
  2517. X
  2518. main()
  2519. X{
  2520. X    char     pattern[80];
  2521. X    char     text[80];
  2522. X
  2523. X    printf("Wildmat tester.  Enter pattern, then strings to test.\n");
  2524. X    printf("A blank line gets prompts for a new pattern; a blank pattern\n");
  2525. X    printf("exits the program.\n\n");
  2526. X
  2527. X    for ( ; ; ) {
  2528. X    printf("Enter pattern:  ");
  2529. X    if (gets(pattern) == NULL)
  2530. X        break;
  2531. X    for ( ; ; ) {
  2532. X        printf("Enter text:  ");
  2533. X        if (gets(text) == NULL)
  2534. X        exit(0);
  2535. X        if (text[0] == '\0')
  2536. X        /* Blank line; go back and get a new pattern. */
  2537. X        break;
  2538. X        printf("      %s\n", wildmat(text, pattern) ? "YES" : "NO");
  2539. X    }
  2540. X    }
  2541. X
  2542. X    exit(0);
  2543. X    /* NOTREACHED */
  2544. X}
  2545. X#endif    /* TEST */
  2546. END_OF_FILE
  2547. if test 2677 -ne `wc -c <'wildmat.c'`; then
  2548.     echo shar: \"'wildmat.c'\" unpacked with wrong size!
  2549. fi
  2550. # end of 'wildmat.c'
  2551. fi
  2552. echo shar: End of shell archive.
  2553. exit 0
  2554.